packages feed

PenroseKiteDart 1.10.1 → 1.11

raw patch · 10 files changed

+900/−373 lines, 10 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- TileLibP3: LN :: a -> P3_HalfTile a
- TileLibP3: LW :: a -> P3_HalfTile a
- TileLibP3: RN :: a -> P3_HalfTile a
- TileLibP3: RW :: a -> P3_HalfTile a
- TileLibP3: class P3_Drawable a
- TileLibP3: class P3_DrawableLabelled a
- TileLibP3: data P3_HalfTile a
- TileLibP3: decompP2toP3 :: Patch -> P3_Patch
- TileLibP3: decompP3toP2 :: P3_Patch -> Patch
- TileLibP3: decompPieceP2toP3 :: Located Piece -> [Located P3_Piece]
- TileLibP3: decompPieceP3toP2 :: Located P3_Piece -> [Located Piece]
- TileLibP3: drawJP3 :: (OKBackend b, P3_Drawable a) => a -> Diagram b
- TileLibP3: drawJPieceP3 :: OKBackend b => P3_Piece -> Diagram b
- TileLibP3: drawP3 :: (OKBackend b, P3_Drawable a) => a -> Diagram b
- TileLibP3: drawP3With :: (P3_Drawable a, OKBackend b) => (P3_Piece -> Diagram b) -> a -> Diagram b
- TileLibP3: drawPieceP3 :: OKBackend b => P3_Piece -> Diagram b
- TileLibP3: drawjP3 :: (OKBackend b, P3_Drawable a) => a -> Diagram b
- TileLibP3: drawjPieceP3 :: OKBackend b => P3_Piece -> Diagram b
- TileLibP3: drawnEdgesP3 :: P3_Piece -> [V2 Double]
- TileLibP3: fillNW :: (OKBackend b, P3_Drawable a, Color cw, Color cn) => cw -> cn -> a -> Diagram b
- TileLibP3: fillOnlyPieceP3 :: (OKBackend b, Color c) => c -> P3_Piece -> Diagram b
- TileLibP3: fillOnlyPieceWN :: (OKBackend b, Color cw, Color cn) => cw -> cn -> P3_Piece -> Diagram b
- TileLibP3: fillPieceWN :: (OKBackend b, Color cw, Color cn) => cw -> cn -> P3_Piece -> Diagram b
- TileLibP3: fillWN :: (OKBackend b, P3_Drawable a, Color cw, Color cn) => cw -> cn -> a -> Diagram b
- TileLibP3: instance Diagrams.Core.Transform.Transformable a => Diagrams.Core.Transform.Transformable (TileLibP3.P3_HalfTile a)
- TileLibP3: instance GHC.Classes.Eq a => GHC.Classes.Eq (TileLibP3.P3_HalfTile a)
- TileLibP3: instance GHC.Internal.Base.Functor TileLibP3.P3_HalfTile
- TileLibP3: instance GHC.Internal.Show.Show a => GHC.Internal.Show.Show (TileLibP3.P3_HalfTile a)
- TileLibP3: instance TileLibP3.P3_Drawable Tgraph.Prelude.Tgraph
- TileLibP3: instance TileLibP3.P3_Drawable Tgraph.Prelude.VPatch
- TileLibP3: instance TileLibP3.P3_Drawable TileLib.Patch
- TileLibP3: instance TileLibP3.P3_Drawable TileLibP3.P3_Patch
- TileLibP3: instance TileLibP3.P3_DrawableLabelled Tgraph.Prelude.Tgraph
- TileLibP3: instance TileLibP3.P3_DrawableLabelled Tgraph.Prelude.VPatch
- TileLibP3: joinVectorP3 :: P3_Piece -> V2 Double
- TileLibP3: labelColourSizeP3 :: (P3_DrawableLabelled a, OKBackend b) => Colour Double -> Measure Double -> (P3_Patch -> Diagram b) -> a -> Diagram b
- TileLibP3: labelSizeP3 :: (OKBackend b, P3_DrawableLabelled a) => Measure Double -> (P3_Patch -> Diagram b) -> a -> Diagram b
- TileLibP3: labelledP3 :: (OKBackend b, P3_DrawableLabelled a) => (P3_Patch -> Diagram b) -> a -> Diagram b
- TileLibP3: type P3_Patch = [Located P3_Piece]
- TileLibP3: type P3_Piece = P3_HalfTile [V2 Double]
+ Tgraph.Prelude: checkConnectedNoCross :: [Dedge] -> Try ()
+ Tgraph.Prelude: makeEVnewMap :: Vertex -> [Dedge] -> Map Dedge Vertex
+ Tgraph.Rhombuses: LN :: a -> HalfTile_P3 a
+ Tgraph.Rhombuses: LW :: a -> HalfTile_P3 a
+ Tgraph.Rhombuses: RN :: a -> HalfTile_P3 a
+ Tgraph.Rhombuses: RW :: a -> HalfTile_P3 a
+ Tgraph.Rhombuses: VPatch_P3 :: VertexLocMap -> [TileFace_P3] -> VPatch_P3
+ Tgraph.Rhombuses: [vLocs_P3] :: VPatch_P3 -> VertexLocMap
+ Tgraph.Rhombuses: [vpFaces_P3] :: VPatch_P3 -> [TileFace_P3]
+ Tgraph.Rhombuses: class DrawableLabelled_P3 a
+ Tgraph.Rhombuses: class Drawable_P3 a
+ Tgraph.Rhombuses: convertVPatch :: [TileFace_P3] -> VPatch -> VPatch_P3
+ Tgraph.Rhombuses: convertVPatch_P3 :: [TileFace] -> VPatch_P3 -> VPatch
+ Tgraph.Rhombuses: data HalfTile_P3 a
+ Tgraph.Rhombuses: data Tgraph_P3
+ Tgraph.Rhombuses: data VPatch_P3
+ Tgraph.Rhombuses: decompPatchP2toP3 :: Patch -> Patch_P3
+ Tgraph.Rhombuses: decompPatchP3toP2 :: Patch_P3 -> Patch
+ Tgraph.Rhombuses: decompPieceP2toP3 :: Located Piece -> [Located Piece_P3]
+ Tgraph.Rhombuses: decompPieceP3toP2 :: Located Piece_P3 -> [Located Piece]
+ Tgraph.Rhombuses: decomposeRhombuses :: Tgraph_P3 -> Tgraph_P3
+ Tgraph.Rhombuses: decomposeToRhombuses :: Tgraph -> Tgraph_P3
+ Tgraph.Rhombuses: decomposeToTgraph :: Tgraph_P3 -> Tgraph
+ Tgraph.Rhombuses: dedges_P3 :: [TileFace_P3] -> [Dedge]
+ Tgraph.Rhombuses: deformVPatch_P3 :: Deformation V2 V2 Double -> VPatch_P3 -> VPatch_P3
+ Tgraph.Rhombuses: drawJPiece_P3 :: OKBackend b => Piece_P3 -> Diagram b
+ Tgraph.Rhombuses: drawJ_P3 :: (OKBackend b, Drawable_P3 a) => a -> Diagram b
+ Tgraph.Rhombuses: drawPiece_P3 :: OKBackend b => Piece_P3 -> Diagram b
+ Tgraph.Rhombuses: drawWith_P3 :: (Drawable_P3 a, OKBackend b) => (Piece_P3 -> Diagram b) -> a -> Diagram b
+ Tgraph.Rhombuses: draw_P3 :: (OKBackend b, Drawable_P3 a) => a -> Diagram b
+ Tgraph.Rhombuses: drawjPiece_P3 :: OKBackend b => Piece_P3 -> Diagram b
+ Tgraph.Rhombuses: drawj_P3 :: (OKBackend b, Drawable_P3 a) => a -> Diagram b
+ Tgraph.Rhombuses: drawnEdges_P3 :: Piece_P3 -> [V2 Double]
+ Tgraph.Rhombuses: dropLabels_P3 :: VPatch_P3 -> Patch_P3
+ Tgraph.Rhombuses: faceCount_P3 :: Tgraph_P3 -> Int
+ Tgraph.Rhombuses: faceVList_P3 :: TileFace_P3 -> [Vertex]
+ Tgraph.Rhombuses: faceVSet_P3 :: TileFace_P3 -> VertexSet
+ Tgraph.Rhombuses: faceVs_P3 :: TileFace_P3 -> (Vertex, Vertex, Vertex)
+ Tgraph.Rhombuses: faces_P3 :: Tgraph_P3 -> [TileFace_P3]
+ Tgraph.Rhombuses: fillNW :: (OKBackend b, Drawable_P3 a, Color cw, Color cn) => cw -> cn -> a -> Diagram b
+ Tgraph.Rhombuses: fillOnlyPieceWN :: (OKBackend b, Color cw, Color cn) => cw -> cn -> Piece_P3 -> Diagram b
+ Tgraph.Rhombuses: fillOnlyPiece_P3 :: (OKBackend b, Color c) => c -> Piece_P3 -> Diagram b
+ Tgraph.Rhombuses: fillPieceWN :: (OKBackend b, Color cw, Color cn) => cw -> cn -> Piece_P3 -> Diagram b
+ Tgraph.Rhombuses: fillWN :: (OKBackend b, Drawable_P3 a, Color cw, Color cn) => cw -> cn -> a -> Diagram b
+ Tgraph.Rhombuses: instance Diagrams.Core.Transform.Transformable Tgraph.Rhombuses.VPatch_P3
+ Tgraph.Rhombuses: instance Diagrams.Core.Transform.Transformable a => Diagrams.Core.Transform.Transformable (Tgraph.Rhombuses.HalfTile_P3 a)
+ Tgraph.Rhombuses: instance Diagrams.Deform.Deformable Tgraph.Rhombuses.VPatch_P3 Tgraph.Rhombuses.VPatch_P3
+ Tgraph.Rhombuses: instance GHC.Classes.Eq a => GHC.Classes.Eq (Tgraph.Rhombuses.HalfTile_P3 a)
+ Tgraph.Rhombuses: instance GHC.Internal.Base.Functor Tgraph.Rhombuses.HalfTile_P3
+ Tgraph.Rhombuses: instance GHC.Internal.Show.Show Tgraph.Rhombuses.Tgraph_P3
+ Tgraph.Rhombuses: instance GHC.Internal.Show.Show Tgraph.Rhombuses.VPatch_P3
+ Tgraph.Rhombuses: instance GHC.Internal.Show.Show a => GHC.Internal.Show.Show (Tgraph.Rhombuses.HalfTile_P3 a)
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.DrawableLabelled_P3 Tgraph.Prelude.Tgraph
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.DrawableLabelled_P3 Tgraph.Prelude.VPatch
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.DrawableLabelled_P3 Tgraph.Rhombuses.Tgraph_P3
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.DrawableLabelled_P3 Tgraph.Rhombuses.VPatch_P3
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.Drawable_P3 Tgraph.Prelude.Tgraph
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.Drawable_P3 Tgraph.Prelude.VPatch
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.Drawable_P3 Tgraph.Rhombuses.Patch_P3
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.Drawable_P3 Tgraph.Rhombuses.Tgraph_P3
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.Drawable_P3 Tgraph.Rhombuses.VPatch_P3
+ Tgraph.Rhombuses: instance Tgraph.Rhombuses.Drawable_P3 TileLib.Patch
+ Tgraph.Rhombuses: isNarrow :: TileFace_P3 -> Bool
+ Tgraph.Rhombuses: isWide :: TileFace_P3 -> Bool
+ Tgraph.Rhombuses: joinVector_P3 :: Piece_P3 -> V2 Double
+ Tgraph.Rhombuses: join_P3 :: TileFace_P3 -> Dedge
+ Tgraph.Rhombuses: labelColourSize_P3 :: (DrawableLabelled_P3 a, OKBackend b) => Colour Double -> Measure Double -> (Patch_P3 -> Diagram b) -> a -> Diagram b
+ Tgraph.Rhombuses: labelSize_P3 :: (OKBackend b, DrawableLabelled_P3 a) => Measure Double -> (Patch_P3 -> Diagram b) -> a -> Diagram b
+ Tgraph.Rhombuses: labelled_P3 :: (OKBackend b, DrawableLabelled_P3 a) => (Patch_P3 -> Diagram b) -> a -> Diagram b
+ Tgraph.Rhombuses: makeVP_P3 :: Tgraph_P3 -> VPatch_P3
+ Tgraph.Rhombuses: maxV_P3 :: [TileFace_P3] -> Int
+ Tgraph.Rhombuses: oppV_P3 :: TileFace_P3 -> Vertex
+ Tgraph.Rhombuses: originV_P3 :: TileFace_P3 -> Vertex
+ Tgraph.Rhombuses: quickComposeToFaces_P3 :: Tgraph -> [TileFace_P3]
+ Tgraph.Rhombuses: quickComposeToRhombuses :: Tgraph -> Tgraph_P3
+ Tgraph.Rhombuses: tileRep_P3 :: HalfTile_P3 a -> a
+ Tgraph.Rhombuses: tryComposeToFaces_P3 :: Tgraph -> Try [TileFace_P3]
+ Tgraph.Rhombuses: tryComposeToRhombuses :: Tgraph -> Try Tgraph_P3
+ Tgraph.Rhombuses: tryConnectedNoCross_P3 :: [TileFace_P3] -> Try Tgraph_P3
+ Tgraph.Rhombuses: type Patch_P3 = [Located Piece_P3]
+ Tgraph.Rhombuses: type Piece_P3 = HalfTile_P3 [V2 Double]
+ Tgraph.Rhombuses: type TileFace_P3 = HalfTile_P3 (Vertex, Vertex, Vertex)
+ Tgraph.Rhombuses: vertexSet_P3 :: [TileFace_P3] -> VertexSet
+ Tgraph.Rhombuses: wingV_P3 :: TileFace_P3 -> Vertex
+ TgraphExamples: composeToRhombusProblem :: OKBackend b => Diagram b

Files

CHANGELOG.md view
@@ -1,5 +1,91 @@ # Revision history for PenroseKiteDart +## version 1.11++Significant changes to P3 tiling (rhombuses) and drawing P3 style.++- Renamed module TileLibP3 as Tgraph.Rhombuses++- Renamed some P3 functions, types, classes (for consistency)+   - P3_HalfTile renamed as HalfTile_P3+   - P3_Piece renamed as Piece_P3+   - P3_Patch renamed as Patch_P3+   - joinVectorP3 renamed as joinVector_P3+   - drawnEdgesP3 renamed as drawnEdges_P3+   - decompP2toP3 renamed as decompPatchP2toP3+   - decompP3toP2 renamed as decompPatchP3toP2+   - drawPieceP3  renamed as drawPiece_P3+   - drawjPieceP3 renamed as drawjPiece_P3 +   - drawJPieceP3 renamed as drawJPiece_P3+   - P3_Drawable renamed as Drawable_P3+   - P3_DrawableLabelled renamed as DrawableLabelled_P3+   - labelColourSizeP3 renamed as labelColourSize_P3+   - labelSizeP3 renamed as labelSize_P3+   - labelledP3 renamed as labelled_P3+   - drawP3With renamed as drawWith_P3+   - drawP3 renamed as draw_P3+   - drawjP3 renamed as drawj_P3+   - drawJP3 renamed as drawJ_P3+- Added+    - makeEVnewMap+    - checkConnectedNoCross+    - Tgraph_P3()+    - decomposeToRhombuses+    - decomposeToTgraph+    - decomposeRhombuses+    - tryComposeToRhombuses+    - quickComposeToRhombuses+    - TileFace_P3+    - tryConnectedNoCross_P3+    - tryComposeToFaces_P3+    - quickComposeToFaces_P3+    - faces_P3+    - maxV_P3+    - vertexSet_P3+    - faceVSet_P3+    - faceVs_P3+    - faceVList_P3+    - originV_P3+    - oppV_P3+    - wingV_P3+    - join_P3+    - isWide+    - isNarrow+    - dedges_P3+    - VPatch_P3(vLocs_P3,vpFaces_P3)+    - makeVP_P3+    - dropLabels_P3+    - convertVPatch_P3+    - convertVPatch+    - deformVPatch_P3+    - HalfTile_P3(LW,RW,LN,RN)+    - tileRep_P3+    - joinVector_P3+    - drawnEdges_P3+    - Piece_P3+    - decompPieceP2toP3+    - decompPieceP3toP2+    - Patch_P3+    - decompPatchP2toP3+    - decompPatchP3toP2+    - drawPiece_P3+    - drawjPiece_P3+    - drawJPiece_P3+    - fillOnlyPiece_P3+    - fillOnlyPieceWN+    - fillPieceWN+    - Drawable_P3(..)+    - draw_P3+    - drawj_P3+    - drawJ_P3+    - fillWN+    - fillNW+    - DrawableLabelled_P3(..)+    - labelSize_P3+    - labelled_P3+    - composeToRhombusProblem (in TgraphExamples)++ ## version 1.10.1  -  VPatch is now deformable
PenroseKiteDart.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           PenroseKiteDart-version:        1.10.1+version:        1.11 synopsis:       Library to explore Penrose's Kite and Dart Tilings. description:    Library to explore Penrose's Kite and Dart Tilings using Haskell Diagrams. Please see README.md category:       Graphics@@ -31,7 +31,6 @@       CheckBackend       HalfTile       TileLib-      TileLibP3       Try       Tgraph.Prelude       Tgraph.Decompose@@ -40,6 +39,7 @@       Tgraph.Relabelling       Tgraph.Extras       Tgraph.Grid+      Tgraph.Rhombuses       TgraphExamples   other-modules:       Paths_PenroseKiteDart
benchmark/Bench.hs view
@@ -34,16 +34,24 @@      _  <- traceMarkerIO "finished (unchecked) composing"       wait      _ <- traceMarkerIO "starting checked compose" -     let !newcfkD = {-# SCC "checkedCompose" #-} compose $ recoverGraph fkD+     let !newcfkD = {-# SCC "checkedCompose" #-} compose fkD      putStrLn $ "Number of faces of new checked compose is "                              ++ show (faceCount newcfkD)      _  <- traceMarkerIO "finished checked compose" +{-      wait+     _ <- traceMarkerIO "starting tryComposeToRhombuses" +     let !crfkD = {-# SCC "tryComposeToRhombuses" #-} runTry $ tryComposeToRhombuses $ recoverGraph fkD+     putStrLn $ "Number of faces of quickCompose is " +                            ++ show (faceCount_P3 crfkD)+     _  <- traceMarkerIO "finished tryComposeToRhombuses" +     wait      _ <- traceMarkerIO "starting quickCompose" -     let !qcfkD = {-# SCC "quickCompose" #-} quickCompose $ recoverGraph fkD+     let !qcfkD = {-# SCC "quickCompose" #-} quickCompose fkD      putStrLn $ "Number of faces of quickCompose is "                              ++ show (faceCount qcfkD)      _  <- traceMarkerIO "finished quickCompose" + -}      return ()       
src/HalfTile.hs view
@@ -68,10 +68,10 @@ -- {-# INLINE tileRep #-} -- |return the representation of a half-tile tileRep:: HalfTile rep -> rep-tileRep (LD !r) = r-tileRep (RD !r) = r-tileRep (LK !r) = r-tileRep (RK !r) = r+tileRep (LD r) = r+tileRep (RD r) = r+tileRep (LK r) = r+tileRep (RK r) = r  -- |half-tile predicate isLD,isRD,isLK,isRK,isDart,isKite :: HalfTile rep -> Bool
src/PKD.hs view
@@ -36,7 +36,7 @@     -- * Smart drawing of Tgraphs and other extras    , module Tgraph.Extras     -- * Converting to P3 (rhombus) tilings and drawing-  , module TileLibP3+  , module Tgraph.Rhombuses    ) where @@ -47,5 +47,5 @@ import Tgraph.Relabelling import Tgraph.Force import Tgraph.Extras-import TileLibP3+import Tgraph.Rhombuses 
src/Tgraph/Decompose.hs view
@@ -23,9 +23,9 @@   ) where  import Data.Map.Strict(Map)-import qualified Data.Map.Strict as Map ((!), fromList)-import Data.List(sort)+import qualified Data.Map.Strict as Map ((!)) + import Tgraph.Prelude  @@ -47,19 +47,21 @@     pvmap = phiVMap a     newFaces = concatMap (decompFace pvmap) (faces a) + -- |phiVMap fcs produces a finite map from the phi edges (the long edges including kite joins) to assigned new vertices not in fcs. -- Both (a,b) and (b,a) get the same new vertex number. This is used in decompFace, decompFaces and decompose. -- Sort is used to fix order of assigned numbers. -- Exported for use in TrackedTgraphs in Tgraph.Extras module. phiVMap :: HasFaces a => a -> Map Dedge Vertex-phiVMap x = edgeVMap where+phiVMap x = makeEVnewMap (maxV x) (concatMap facePhiEdges (faces x))+{- phiVMap x = edgeVMap where   --phiReps = sort [e | e@(a,b) <- phiEdges fcs, a<b]   phiReps = sort [e | fc <- faces x, e@(a,b) <- facePhiEdges fc , a<b]   newVs = [v+1..v+n]   n = length phiReps   v = maxV x   edgeVMap = Map.fromList $ zip phiReps newVs ++ zip (map reverseD phiReps) newVs -+ -} -- |Decompose a face producing new faces.  -- This requires an edge to vertex map to get a unique new vertex assigned to each phi edge -- (as created by phiVMap).
src/Tgraph/Prelude.hs view
@@ -42,6 +42,7 @@ -- * Tgraph Property Checks   , tryTgraphProps   , tryConnectedNoCross+  , checkConnectedNoCross   , tryCorrectTouchingVs   , hasEdgeLoops   , duplicates@@ -97,6 +98,7 @@   , vertexFMap   , dedgeFMap   , buildEFMap+  , makeEVnewMap   , extractLowestJoin   , lowestJoin     -- * Other Face ops@@ -183,7 +185,7 @@   --, drawEdge   ) where -import Data.List ((\\),intersect,find,nub)+import Data.List ((\\),intersect,find,nub,sort) import Prelude hiding (Foldable(..)) import Data.Foldable (Foldable(..)) import Data.IntMap.Strict(IntMap)@@ -405,7 +407,8 @@                         ,"\n"                         ]            -- makes use of precalculated edges and vertices-      else tryConnectedNoCross' fcs deslist vs+      else do _ <- tryConnectedNoCross' deslist vs+              return $ Tgraph fcs  -- |Checks a list of faces for no crossing boundaries and connectedness. -- (No crossing boundaries and connected implies tile-connected).@@ -415,10 +418,59 @@ -- but can be used alone when other properties are known to hold (e.g. in tryPartCompose) tryConnectedNoCross:: [TileFace] -> Try Tgraph tryConnectedNoCross [] = Right emptyTgraph-tryConnectedNoCross fcs = tryConnectedNoCross' fcs (dedges fcs) (vertexSet fcs)+tryConnectedNoCross fcs = do _ <- tryConnectedNoCross' (dedges fcs) (vertexSet fcs)+                             return (Tgraph fcs) + -- |(not exported) A variant of tryConnectedNoCross with precalculated dedge list and vertex set. -- Checks for no crossing boundaries and connectedness.+-- Returns Right () on passing checks.+-- Returns Left lines if a test fails, where lines describes the problem found.+-- This is used by tryTgraphProps after other checks have been made.+tryConnectedNoCross' :: [Dedge] -> IntSet -> Try ()+tryConnectedNoCross' deslist vs = -- no arguments are null+    let des = Set.fromList deslist+        bes = missingRevSet des -- boundaryESetFrom+        duplicateBVs = duplicates $ verticesForBEs bes+        crossing = not $ null duplicateBVs+        isConnected = null (snd $ connectedBy (bes<>des) (IntSet.findMin vs) vs)+    in if not isConnected+       then failReport+            "tryConnectedNoCross': (Not connected)\n"+       else if crossing+       then failReports+            ["tryConnectedNoCross': Crossing boundaries found at "+            ,show duplicateBVs+            ,"\n"+            ]+       else Right ()++-- |Exported check for connectedness and no crossing boundaries taking just a dedge list.+-- Returns Right () on passing checks.+-- Returns Left lines if a test fails, where lines describes the problem found.+checkConnectedNoCross :: [Dedge] -> Try ()+checkConnectedNoCross [] = Right ()+checkConnectedNoCross deslist = -- not null+    let des = Set.fromList deslist+        bes = missingRevSet des -- boundaryESetFrom+        duplicateBVs = duplicates $ verticesForBEs bes+        crossing = not $ null duplicateBVs+        vs = IntSet.fromList (map fst deslist <> map snd deslist)+        isConnected = null (snd $ connectedBy (bes<>des) (IntSet.findMin vs) vs)+    in if not isConnected+       then failReport+            "checkConnectedNoCross: (Not connected)\n"+       else if crossing+       then failReports+            ["checkConnectedNoCross: Crossing boundaries found at "+            ,show duplicateBVs+            ,"\n"+            ]+       else Right ()++{- OLDER+-- |(not exported) A variant of tryConnectedNoCross with precalculated dedge list and vertex set.+-- Checks for no crossing boundaries and connectedness. -- The given dedge list must be all the dedges in the faces,  -- and the given vertex set must be all the vertices in the faces. -- The faces must not be null.@@ -432,8 +484,8 @@         bes = missingRevSet des -- boundaryESetFrom         duplicateBVs = duplicates $ verticesForBEs bes         crossing = not $ null duplicateBVs-        connectedFcs = null (snd $ connectedBy (bes<>des) (IntSet.findMin vs) vs)-    in if not connectedFcs+        isConnected = null (snd $ connectedBy (bes<>des) (IntSet.findMin vs) vs)+    in if not isConnected        then failReports             ["tryConnectedNoCross: Non-valid Tgraph (Not connected)\n"             ,"with faces\n"@@ -450,6 +502,7 @@             ,"\n"             ]        else Right (Tgraph fcs)+ -}  -- |Used in testing. ---Checks if there are repeated vertices within any TileFace for a list of TileFaces.@@ -544,7 +597,6 @@  -- |There are crossing boundaries if vertices occur more than once -- in the boundary vertices.- crossingBoundaries :: HasFaces a => a  -> Bool crossingBoundaries = not . null . crossingBVs -- Used in testing @@ -753,21 +805,21 @@  -- |triple of face vertices in order clockwise starting with origin - tileRep specialised to TileFace faceVs::TileFace -> (Vertex,Vertex,Vertex)-faceVs = evalTriple . tileRep+faceVs = tileRep --- |force evaluation of a triple+{- -- |force evaluation of a triple evalTriple :: (Int,Int,Int) -> (Int,Int,Int) evalTriple tr@(a,b,c) = a `seq` b `seq` c `seq` tr-+ -} -- |list of (three) face vertices in order clockwise starting with origin faceVList::TileFace -> [Vertex]--- faceVList = (\(x,y,z) -> [x,y,z]) . faceVs-faceVList f = [a,b,c] where (a,b,c) = faceVs f+faceVList = asList . faceVs where+    asList (a,b,c) = [a,b,c]+ -- |the set of vertices of a face faceVSet :: TileFace -> VertexSet--- faceVSet = IntSet.fromList . faceVList-faceVSet f = IntSet.insert a $ IntSet.insert b $ IntSet.insert c IntSet.empty-             where (a,b,c) = faceVs f+faceVSet = asSet . faceVs where+    asSet (a,b,c) = IntSet.insert a $ IntSet.insert b $ IntSet.insert c IntSet.empty   -- |firstV, secondV and thirdV vertices of a face are counted clockwise starting with the origin@@ -823,12 +875,7 @@ isAtV:: Vertex -> TileFace -> Bool isAtV v f = v==a || v==b || v==c      where (a,b,c) = faceVs f-{-     -isAtV v (LD(a,b,c))  =  v==a || v==b || v==c-isAtV v (RD(a,b,c))  =  v==a || v==b || v==c-isAtV v (LK(a,b,c))  =  v==a || v==b || v==c-isAtV v (RK(a,b,c))  =  v==a || v==b || v==c- -}+ -- |hasVIn vs f - asks if face f has an element of vs as a vertex hasVIn:: [Vertex] -> TileFace -> Bool hasVIn vs face = not $ null $ faceVList face `intersect` vs@@ -1040,6 +1087,20 @@ -- | look up a face for an edge in an edge-face map faceForEdge :: Dedge -> Map Dedge TileFace ->  Maybe TileFace faceForEdge = Map.lookup++-- | Given a starting int v and a list of directed edges des (mixed, not necessarily both directions)+-- create a map from edges to new integers above v, such that:+-- 1) The edges are both directions of edges in des without repetitions. +-- 2) Both (a,b) and (b,a) get the same integer.+-- The edges get consecutive integers after being sorted+-- (where if a>b then (a,b) gets the integer assigned to (b,a)).+makeEVnewMap :: Vertex -> [Dedge] -> Map Dedge Vertex+makeEVnewMap v des = themap where+    themap = Map.fromList $ zip reps newVs ++ zip (map reverseD reps) newVs+    reps = sort [e | e@(a,b) <- missingRevs des <> des , a<b]+    newVs = [v+1..v+n]+    n = length reps+  -- |Given a tileface (face) and a map from each directed edge to the (unique) tileface containing it (efMap) -- return the list of edge neighbours of face.
+ src/Tgraph/Rhombuses.hs view
@@ -0,0 +1,695 @@+{-|+Module      : Rhombuses+Description : Converting between Kites and Darts (P2 tiles) to Rhombuses (P3 tiles) and drawing+Copyright   : (c) Chris Reade, 2021+License     : BSD-style+Maintainer  : chrisreade@mac.com+Stability   : experimental++This module introduces Penrose\'s P3 tilings (narrow and wide rhombuses).+It includes HalfTile_P3, Piece_P3, Patch_P3, VPatch_P3, Tgraph_P3 to represent and draw+rhombuses plus conversion to and from Darts and Kites (the P2 tiles).+A class Drawable_P3 is introduced with instance Patch_P3, VPatch_P3, Tgraph_P3+as well as Patch, VPatch, Tgraph.+A class DrawableLabelled_P3 is introduced with instance VPatch_P3, Tgraph_P3+as well as VPatch, Tgraph.+and generalised drawing functions for drawing P3 tilings.+-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE FlexibleContexts          #-}+{-# LANGUAGE TypeFamilies              #-}+{-# LANGUAGE FlexibleInstances         #-} -- needed for Drawable_P3 Patch_P3+{-# LANGUAGE Strict                    #-}+-- {-# LANGUAGE TypeOperators             #-} -- needed for type equality constraints ~++module Tgraph.Rhombuses +  ( +  -- * Tgraph_P3+    Tgraph_P3()+  , decomposeToRhombuses+  , decomposeToTgraph+  , decomposeRhombuses+  , tryComposeToRhombuses+  , quickComposeToRhombuses+  -- * TileFace_P3+  , TileFace_P3+  , tryConnectedNoCross_P3+  , tryComposeToFaces_P3+  , quickComposeToFaces_P3+  , faceCount_P3+  , faces_P3+  , maxV_P3+  , vertexSet_P3+  , faceVSet_P3+  , faceVs_P3+  , faceVList_P3+  , originV_P3+  , oppV_P3+  , wingV_P3+  , join_P3+  , isWide+  , isNarrow+  , dedges_P3+  -- * VPatch_P3+  , VPatch_P3(..)+  , makeVP_P3+  , dropLabels_P3+  , convertVPatch_P3+  , convertVPatch+  , deformVPatch_P3+  -- * HalfTile_P3+  , HalfTile_P3(..)+  , tileRep_P3+  , joinVector_P3+  , drawnEdges_P3+  -- * Piece_P3s+  , Piece_P3+  -- * Converting (located) Pieces+  , decompPieceP2toP3+  , decompPieceP3toP2+  -- * Converting Patches+  , Patch_P3+  , decompPatchP2toP3+  , decompPatchP3toP2+  -- * Drawing Piece_P3s+  , drawPiece_P3+  , drawjPiece_P3+  , drawJPiece_P3+  , fillOnlyPiece_P3+  , fillOnlyPieceWN+  , fillPieceWN+   -- * Drawable_P3 Class+  , Drawable_P3(..)+  -- * Drawing functions producing P3 Rhombuses+  , draw_P3+  , drawj_P3+  , drawJ_P3+  , fillWN+  , fillNW+  -- * DrawableLabelled_P3 Class+  , DrawableLabelled_P3(..)+  -- * Adding labels to functions producing P3 Rhombuses+  , labelSize_P3+  , labelled_P3+  ) where++import Diagrams.Prelude+--import Diagrams.TwoD.Text (Text) -- now in CheckBackend++import CheckBackend+import HalfTile+import TileLib+import Tgraph.Prelude+import Tgraph.Decompose ( phiVMap )+import Tgraph.Force (makeBoundaryState, boundaryEdgeFilter, isDartOrigin)+import Tgraph.Compose ( DartWingInfo(largeKiteCentres), tryGetDartWingInfo)++import qualified Data.Map.Strict as Map ( (!),empty,elems,lookup,insert,delete)+import qualified Data.IntMap.Strict as VMap (fromList,toList,lookup,filterWithKey,keys,map,keysSet)+import qualified Data.IntSet as IntSet(empty,insert,findMax,member,null,difference)+import Data.List ( (\\) )+-- |Tgraph_P3 is a P3 (Rhombus) version of Tgraph+newtype Tgraph_P3 = Tgraph_P3 [TileFace_P3] deriving Show++-- |TileFace_P3 is a P3 (half rhombus) analagous to TileFace+type TileFace_P3 = HalfTile_P3 (Vertex,Vertex,Vertex)++-- |Given a list of half rhombuses, check they are connected with no crossing boundary+-- producing a Tgraph_P3 when successful.+tryConnectedNoCross_P3  :: [TileFace_P3] -> Try Tgraph_P3+tryConnectedNoCross_P3  rs = do+    _ <- onFail "    tryConnectedNoCross_P3- : result has crossing boundary or is not connected\n" $+         checkConnectedNoCross (dedges_P3 rs)+    return (Tgraph_P3 rs)++-- |Decompose a Tgraph into Tgraph_P3 (rhombuses)+-- The new vertex numbers are generated with phiVMap from Tgraph.Decompose+decomposeToRhombuses :: Tgraph -> Tgraph_P3+decomposeToRhombuses g = Tgraph_P3 rs where+   rs = concatMap convert (faces g)+   newVFor = phiVMap g --makeEVnewMap (maxV g) (map joinE $ filter isKite $ faces g)+ --  newVFor = makeEVnewMap (maxV g) (map joinE $ filter isKite $ faces g)+   convert (LK(a,b,c)) = [ RW (a,b,x), RN (c,x,b) ] where x = newVFor Map.! (a,c)+   convert (RK(a,b,c)) = [ LW (a,x,c), LN (b,c,x) ] where x = newVFor Map.! (a,b)+   convert (LD(a,b,c)) = [ RW(c,a,b) ]+   convert (RD(a,b,c)) = [ LW(b,c,a) ]++-- |decompose a Tgraph_P3 (rhombuses) to a Tgraph+decomposeToTgraph :: Tgraph_P3 -> Tgraph+decomposeToTgraph (Tgraph_P3 rs) = makeTgraph (concatMap split rs) where+  split (RN(a,b,c)) = [LK(c,a,b)]+  split (LN(a,b,c)) = [RK(b,c,a)]+  split (RW(a,b,c)) = [LD(a,x,c), RK(b,c,x)] where x = (Map.!) newVFor (a,b)+  split (LW(a,b,c)) = [RD(a,b,x), LK(c,x,b)] where x = (Map.!) newVFor (a,c)+  newVFor = makeEVnewMap v (map join_P3 (filter isWide rs))+  v = maxV_P3 rs++-- |Decompose a Tgraph_P3 (via an intermediate Tgraph)+decomposeRhombuses :: Tgraph_P3 -> Tgraph_P3+decomposeRhombuses = decomposeToRhombuses . decomposeToTgraph+++-- | Try to compose a Tgraph to Tgraph_P3 (rhombuses).+-- This can fail with crossing boundaries even on a forced Tgraph (e.g. force sun3Dart)+-- It can also fail on an incorrect Tgraph (it uses tryGetDartWingInfo which uses tryForce).+--+-- First convert all halftile pairs sharing a short edge+-- (dart and kite -> half Wide rhombus; kite and kite -> full Narrow rhombus).+-- Then convert half kites with a boundary short edge that do not have an unknown oppV.+-- Drop all other half kites and darts with a short edge on the boundary.+tryComposeToRhombuses :: Tgraph -> Try Tgraph_P3+tryComposeToRhombuses g = +     do rhombs <- tryComposeToFaces_P3 g+        onFail "tryComposeToRhombuses: result has crossing boundary or is not connected\n" +             $ tryConnectedNoCross_P3 rhombs++-- | Try to compose a Tgraph to Rhombuses (TileFace_P3).+-- This can fail with crossing boundaries even on a forced Tgraph (e.g. force sun3Dart)+-- It can also fail on an incorrect Tgraph (it uses tryGetDartWingInfo which uses tryForce).+--+-- First convert all halftile pairs sharing a short edge+-- (dart and kite -> half Wide rhombus; kite and kite -> full Narrow rhombus).+-- Then convert half kites with a boundary short edge that do not have an unknown oppV.+-- Drop all other half kites and darts with a short edge on the boundary.+tryComposeToFaces_P3 :: Tgraph -> Try [TileFace_P3]+tryComposeToFaces_P3 g = +     do dwi <- tryGetDartWingInfo g+        return $ composeRhombs (largeKiteCentres dwi) (faces g)+  where+  composeRhombs lkcs fcs = extraNs ++ rhombs1 where+    (rhombs1, remainders) = process ([], Map.empty) fcs+    ordrd p@(a,b) | a<b = p+                    | otherwise = (b,a)+    -- process keeps and produces a pair (rhombuses, map)+    -- The rhombuses are a result of combining two (P2) halftiles with matching short edge.+    -- The map stores single half kites or darts not yet matched, keyed by ordered short edge.+    -- The process deletes map entries that get combined as a rhombus.+    -- Thus the final map has unmatched kites and darts.+    process (ans,m) [] = (ans,Map.elems m) +    process (ans,m) (f:more) +        = let sh = ordrd (reverseD (shortE f))+            in case Map.lookup sh m of+            Nothing -> process (ans, Map.insert sh f m) more+            Just f' -> process (combine f f' ++ans, Map.delete sh m) more+        -- kite wing becomes origin of narrow rhombus                   +    combine (LK(a,b,c)) (RK(d,_,_)) = [RN(b,c,a),LN(b,d,c)]+    combine (RK(d,c,b)) (LK(a,_,_)) = [LN(b,d,c),RN(b,c,a)]+    -- dart origin becomes origin of wide rhombus+    combine (LD(a,_,c)) (RK(d,_,_)) = [RW(a,d,c)]+    combine (RK(d,c,_)) (LD(a,_,_)) = [RW(a,d,c)]+    combine (RD(a,b,_)) (LK(d,_,_)) = [LW(a,b,d)]+    combine (LK(d,_,b)) (RD(a,_,_)) = [LW(a,b,d)]+    combine _ _ = error "tryComposeToRhombuses (combine): non matching pair of faces"+    -- convert candidate half kites with boundary short edge.+    extraNs = map convert candidates+    -- candidate is kite with short edge on boundary and+    -- kite oppV is a largeKiteCentre (not an unknown)+    candidates  = filter (\f -> isKite f && (oppV f `elem` lkcs)) remainders+    -- kite wing becomes origin of narrow rhombus half+    convert (LK(a,b,c)) = RN(b,c,a)+    convert (RK(d,c,b)) = LN(b,d,c)+    convert _ = error "tryComposeToRhombuses (convert) found dart"++-- | (quick) Compose a Tgraph to Tgraph_P3 (rhombuses).+-- This is an approximation for unforced Tgraphs, avoiding use of force.+-- It can fail with crossing boundaries even on a forced Tgraph (e.g. force sun3Dart)+--+-- First convert all halftile pairs sharing a short edge+-- (dart and kite -> half Wide rhombus; kite and kite -> full Narrow rhombus).+-- Then convert half kites with a boundary short edge that share their long edge with a dart.+-- Drop all other half kites and darts with a short edge on the boundary.+-- Thus information can be lost in the conversion. +quickComposeToRhombuses :: Tgraph -> Tgraph_P3+quickComposeToRhombuses = runTry . tryConnectedNoCross_P3 . quickComposeToFaces_P3++-- | (quick) Compose Rhombuses (TileFace_P3) from a Tgraph+-- This is an approximation for unforced Tgraphs, avoiding use of force.+--+-- First convert all halftile pairs sharing a short edge+-- (dart and kite -> half Wide rhombus; kite and kite -> full Narrow rhombus).+-- Then convert half kites with a boundary short edge that share their long edge with a dart.+-- Drop all other half kites and darts with a short edge on the boundary.+-- Thus information can be lost in the conversion. +quickComposeToFaces_P3 :: Tgraph -> [TileFace_P3]+quickComposeToFaces_P3 g = rhombs where+  rhombs = extraNs ++ process Map.empty (faces g) +  ordrd p@(a,b) | a<b = p+                | otherwise = (b,a)+  process _ [] = [] -- the map m stores single halftiles, keyed by ordered short edge+  process m (f:more) = let sh = ordrd (reverseD (shortE f))+                       in case Map.lookup sh m of+                          Nothing -> process (Map.insert sh f m) more+                          Just f' -> combine f f' ++ process m more+    -- kite wing becomes origin of narrow rhombus                   +  combine (LK(a,b,c)) (RK(d,_,_)) = [RN(b,c,a),LN(b,d,c)]+  combine (RK(d,c,b)) (LK(a,_,_)) = [LN(b,d,c),RN(b,c,a)]+  -- dart origin becomes origin of wide rhombus+  combine (LD(a,_,c)) (RK(d,_,_)) = [RW(a,d,c)]+  combine (RK(d,c,_)) (LD(a,_,_)) = [RW(a,d,c)]+  combine (RD(a,b,_)) (LK(d,_,_)) = [LW(a,b,d)]+  combine (LK(d,_,b)) (RD(a,_,_)) = [LW(a,b,d)]+  combine _ _ = error "composeToRhombuses (combine): non matching pair of faces"+  -- convert candidate half kites with boundary short edge.+  extraNs = let bs = makeBoundaryState g+                ks = map snd $ boundaryEdgeFilter Short candidate bs (boundary bs)+            in map convert ks+  -- candidate is kite with short edge on boundary and+  -- dart origin at kite wing (i.e. kite wing is king or queen)+  candidate bs f =  isKite f && isDartOrigin bs (wingV f)+  -- kite wing becomes origin of narrow rhombus half+  convert (LK(a,b,c)) = RN(b,c,a)+  convert (RK(d,c,b)) = LN(b,d,c)+  convert _ = error "composeToRhombuses (convert) found dart"++-- |Count the half rhombuses+faceCount_P3 :: Tgraph_P3 -> Int+faceCount_P3 = length . faces_P3++-- |Get the TileFace_P3 list from a Tgraph_P3+faces_P3 :: Tgraph_P3 -> [TileFace_P3]+faces_P3 (Tgraph_P3 rs) = rs++-- | max vertex in a list of TileFace_P3 (0 for the empty list)+maxV_P3 :: [TileFace_P3] -> Int+maxV_P3 [] = 0+maxV_P3 rs = IntSet.findMax $ vertexSet_P3 rs++-- | set of vertices in a list of TileFace_P3+vertexSet_P3 :: [TileFace_P3] -> VertexSet+vertexSet_P3 = mconcat . map faceVSet_P3++-- | set of vertices in a TileFace_P3+faceVSet_P3 :: TileFace_P3 -> VertexSet+faceVSet_P3 r = IntSet.insert a $ IntSet.insert b $ IntSet.insert c IntSet.empty+             where (a,b,c) = faceVs_P3 r ++-- | triple of vertices in a TileFace_P3 (clockwise from origin)          +faceVs_P3 :: TileFace_P3 -> (Vertex, Vertex, Vertex)+faceVs_P3 (LW tr) =  tr+faceVs_P3 (RW tr) =  tr+faceVs_P3 (LN tr) =  tr+faceVs_P3 (RN tr) =  tr++-- | list of 3 vertices in a TileFace_P3 (clockwise from origin)+faceVList_P3 :: TileFace_P3 -> [Vertex]+faceVList_P3 r = [a,b,c] where (a,b,c) = faceVs_P3 r++-- | origin vertex of a TileFace_P3+originV_P3 :: TileFace_P3 -> Vertex+originV_P3 r = a where (a,_,_) = faceVs_P3 r++-- | opp vertex of a TileFace_P3+oppV_P3 :: TileFace_P3 -> Vertex+oppV_P3 (LW(_,_,c)) = c+oppV_P3 (RW(_,b,_)) = b+oppV_P3 (LN(_,_,c)) = c+oppV_P3 (RN(_,b,_)) = b++-- | wing vertex of a TileFace_P3+wingV_P3 :: TileFace_P3 -> Vertex+wingV_P3 (LW(_,b,_)) = b+wingV_P3 (RW(_,_,c)) = c+wingV_P3 (LN(_,b,_)) = b+wingV_P3 (RN(_,_,c)) = c++-- | join edge of a TileFace_P3 (clockwise = toward origin for LW and LN, away for RW and RN)+join_P3 :: TileFace_P3 -> Dedge+join_P3 (LW(a,_,c)) = (c,a)+join_P3 (RW(a,b,_)) = (a,b)+join_P3 (LN(a,_,c)) = (c,a)+join_P3 (RN(a,b,_)) = (a,b)++-- | Is the half rhombus a wide one (LW,RW)?+isWide :: TileFace_P3 -> Bool+isWide (LW _) = True+isWide (RW _) = True+isWide _      = False++-- | Is the half rhombus a narrow one (LN,RN)?+isNarrow :: TileFace_P3 -> Bool+isNarrow = not . isWide++-- |Directed edges of a list of half rhombuses (clockwise round each )+dedges_P3 :: [TileFace_P3] -> [Dedge]+dedges_P3 = concatMap (delist . faceVs_P3)+   where delist (a,b,c) = [(a,b),(b,c),(c,a)]++-- |VPatch_P3 is a version of VPatch for TileFace_P3s (vertex locations are the same - VertexLocMap)+data VPatch_P3 = VPatch_P3 {vLocs_P3 :: VertexLocMap, vpFaces_P3 :: [TileFace_P3]} deriving Show++-- |needed for making VPatch_P3 transformable+type instance V VPatch_P3 = V2+-- |needed for making VPatch_P3 transformable+type instance N VPatch_P3 = Double++-- |A VPatch_P3 can be transformed.+instance Transformable VPatch_P3 where+    transform :: Transformation V2 Double -> VPatch_P3 -> VPatch_P3+    transform t vp3 = vp3 {vLocs_P3 = VMap.map (transform t) (vLocs_P3 vp3)}++-- | A VPatch_P3 can be deformed+instance Deformable VPatch_P3 VPatch_P3 where+   deform :: Deformation V2 V2 Double -> VPatch_P3 -> VPatch_P3+   deform d vp = vp{vLocs_P3 = VMap.map (deform d) (vLocs_P3 vp)}++   deform' :: Double -> Deformation V2 V2 Double -> VPatch_P3 -> VPatch_P3+   deform' r d vp = vp{vLocs_P3 = VMap.map (deform' r d) (vLocs_P3 vp)}++-- | Explicitly typed instance of deform for a VPatch_P3+-- (This can avoid the need for type annotations when using deform)+deformVPatch_P3 :: Deformation V2 V2 Double -> VPatch_P3 -> VPatch_P3+deformVPatch_P3 = deform++-- |Create a VPatch_P3 from a Tgraph_P3 (uses decomposeToTgraph)+makeVP_P3 :: Tgraph_P3 -> VPatch_P3+makeVP_P3 p@(Tgraph_P3 rs) = VPatch_P3 {vLocs_P3 = vlocsP3 , vpFaces_P3  = rs} where+    vlocs = locateGraphVertices (decomposeToTgraph p)+    vs = vertexSet_P3 rs+    vlocsP3 = VMap.filterWithKey (\ v _ -> v `IntSet.member` vs) vlocs++-- | Convert a VPatch_P3 to a P3_Patch (by dropping labels and calculating vectors)+dropLabels_P3 :: VPatch_P3 -> Patch_P3+dropLabels_P3 vp = map convert (vpFaces_P3 vp) where+   locations = vLocs_P3 vp+   convert face = case (VMap.lookup (originV_P3 face) locations , VMap.lookup (wingV_P3 face) locations, VMap.lookup (oppV_P3 face) locations) of +    (Just p, Just p', Just p'') -> fmap (const [p' .-. p, p'' .-. p']) face `at` p -- using HalfTile functor fmap+    _ -> error $ "dropLabelsP3': Vertex location not found for some vertices:\n    "+                 ++ show (faceVList_P3 face \\ VMap.keys locations)  ++ "\n"++-- | Convert a VPatch to a VPatch_P3 by substituting P3 faces.+-- A check is made to ensure vertices in the P3 faces are keys in the location map,+-- raising an error if any are missing.+convertVPatch :: [TileFace_P3] -> VPatch -> VPatch_P3+convertVPatch rs vp+      | IntSet.null diffSet = VPatch_P3 {vLocs_P3 = vlocsP3, vpFaces_P3 = rs}+      | otherwise = error $ "convertVPatch: missing locations for: "+                             ++ show diffSet ++ "\n"+  where+    vs = vertexSet_P3 rs+    vlocs = vLocs vp+    source = VMap.keysSet vlocs+    diffSet = IntSet.difference vs source+    vlocsP3 = VMap.filterWithKey (\ v _ -> v `IntSet.member` vs) vlocs++-- | Convert a VPatch_P3 to a VPatch by substituting (dart,kite) faces.+-- A check is made to ensure vertices in the faces are keys in the location map,+-- raising an error if any are missing.+convertVPatch_P3 :: [TileFace] -> VPatch_P3 -> VPatch+convertVPatch_P3 fcs vp3+      | IntSet.null diffSet = VPatch {vLocs = vlocs, vpFaces = fcs}+      | otherwise = error $ "convertVPatch: missing locations for: "+                             ++ show diffSet ++ "\n"+  where+    vs = vertexSet fcs+    vlocsP3 = vLocs_P3 vp3+    source = VMap.keysSet vlocsP3+    diffSet = IntSet.difference vs source+    vlocs = VMap.filterWithKey (\ v _ -> v `IntSet.member` vs) vlocsP3+++-- | Penrose P3 Tiling uses wide and narrow rhombuses+-- These are split into half tiles (triangles) as with kites and darts+data HalfTile_P3 a+   = LW a -- ^ Left Wide Rhombus+   | RW a -- ^ Right Wide Rhombus+   | LN a -- ^ Left Narrow Rhombus+   | RN a -- ^ Right Narrow Rhombus+   deriving (Show,Eq)++{-# INLINE tileRep_P3 #-}+-- | tileRep_P3 produces the representation without the label (LW,RW,LN,RN)+tileRep_P3 :: HalfTile_P3 a -> a+tileRep_P3 (LW a) = a+tileRep_P3 (RW a) = a+tileRep_P3 (LN a) = a+tileRep_P3 (RN a) = a++-- |Needed for Transformable instance of HalfTile_P3 - requires TypeFamilies+type instance N (HalfTile_P3 a) = N a+-- |Needed for Transformable instance of HalfTile_P3 - requires TypeFamilies+type instance V (HalfTile_P3 a) = V a+-- |HalfTile_P3 inherits Transformable  - Requires FlexibleInstances+instance Transformable a => Transformable (HalfTile_P3 a) where+    transform t = fmap (transform t)++-- |A Piece_P3 is a HalfTile_P3 with a list of two vectors for the drawn edges.+-- The join vector for a wide rhombus is on the long diagonal,+-- and the join vector for a narrow rhombus is along the short diagonal.+-- The choice of which vertex is the origin is derived from conversions+-- from Darts and Kites (P2 tilings) +type Piece_P3 = HalfTile_P3 [V2 Double]++-- |The drawn edges of a Piece_P3 excluding the join edge (as a list of vectors)+-- starting from the origin.+drawnEdges_P3 :: Piece_P3 -> [V2 Double]+drawnEdges_P3 = tileRep_P3++-- |The join edge vector of a Piece_P3 (from origin)+joinVector_P3 :: Piece_P3 -> V2 Double+joinVector_P3 = sumV . drawnEdges_P3++-- |Make HalfTile_P3 a Functor+instance Functor HalfTile_P3 where+    fmap f (LW rep) = LW (f rep)+    fmap f (RW rep) = RW (f rep)+    fmap f (LN rep) = LN (f rep)+    fmap f (RN rep) = RN (f rep)++-- |Converting from P2 to P3 tilings at the Patch level.+-- Half darts become half wide rhombuses (LD->RW,RD->LW).+-- The rhombus origin is the dart wing, the rhombus opp is the dart origin, so+-- the rhombus join is the dart long edge.+-- Half kites are decomposed to a half wide and a half narrow rhombus+-- (LK -> RW and RN, RK -> LW and LN).+-- For wide rhombuses, the origin is the kite origin and rhombus opp is the kite wing+-- (the join is the kite long edge).+-- For narrow rhombuses, the origin is the kite opp and the rhombus wing is the kite opp+-- (the join is toward the kite origin.)+decompPieceP2toP3 :: Located Piece -> [Located Piece_P3]+decompPieceP2toP3 lp = case viewLoc lp of+    (p, LK [z1,z2]) -> [ RW [s1, s2] `at` p+                       , RN [negate z2, negate s2] `at` p.+^j+                       ]+        where j = sumV [z1,z2]+              s1 = (phi-1) *^ j+              s2 = z1 ^-^ s1+    (p, RK [z1,z2]) -> [ LW [s1, s2] `at` p+                       , LN [negate z2, negate s2] `at` p.+^j+                       ]+        where j = sumV [z1,z2]+              s1 = (phi-1) *^ j+              s2 = z1 ^-^ s1+    (p, LD [z1,z2]) -> [ RW [z2,s1] `at` p.+^ z1]+        where s1 = negate (sumV [z1,z2])+    (p, RD [z1,z2]) -> [ LW [z2,s1] `at` p.+^ z1]+        where s1 = negate (sumV [z1,z2])+    other -> error $ "decompPieceP2toP3: " ++ show other ++ "/n"++-- |Converting located pieces from P3 to P2 tilings.+-- Half narrow rhombuses become half kites (LN->RK,RN->LK).+-- The rhombus wing becomes the kite origin and the rhombus origin becomes the kite wing.+-- Half wide rhombuses are decomposed to a half dart and a half kite+-- (RW -> LD and RK, LW -> RD and LK).+-- The wide rhombus origin becomes the dart origin, and the wide rhombus opp becomes the kite origin.+-- The wide rhombus wing becomes both the kite opp and dart wing.+decompPieceP3toP2 :: Located Piece_P3 -> [Located Piece]+decompPieceP3toP2 lp = case viewLoc lp of+    (p, LW [z1,z2]) -> +        [ RD [z1,s] `at` p+        , LK [ (1-phi)*^j, negate s] `at` (p.+^j)+        ] where j = sumV [z1,z2]+                s = (2-phi) *^ j ^-^ z1+    (p, RW [z1,z2]) -> +        [ LD [z1,s] `at` p+        , RK [ (1-phi)*^j, negate s] `at` (p.+^j)+        ] where j  = sumV [z1,z2]+                s = (2-phi) *^ j ^-^ z1+    (p, LN [z1,z2]) -> [ RK [negate z1, sumV [z1,z2]] `at` p .+^ z1]+    (p, RN [z1,z2]) -> [ LK [negate z1, sumV [z1,z2]] `at` p .+^ z1]+    other -> error $ "decompPieceP3toP2: " ++ show other ++ "/n"+++-- | a Patch_P3 is analagous to a Patch (but for for Piece_P3s)+type Patch_P3 =  [Located Piece_P3]++-- |Conversion from a Patch to a Patch_P3 (Kites and Darts to Rhombuses)+decompPatchP2toP3 :: Patch -> Patch_P3+decompPatchP2toP3 = concatMap decompPieceP2toP3++-- |Conversion from a Patch_P3 to a Patch (Rhombuses to Kites and Darts)+-- Note this does not reverse decompPatchP2toP3, but the combination+-- decompPatchP3toP2 . decompPatchP2toP3 is equivalent to a decompose operation (decompPatch)+decompPatchP3toP2 :: Patch_P3 -> Patch+decompPatchP3toP2 = concatMap decompPieceP3toP2+++-- |Draws the two drawn edges of a Piece_P3+drawPiece_P3 :: OKBackend b => Piece_P3 -> Diagram b+drawPiece_P3 = strokeLine . fromOffsets . drawnEdges_P3+++-- |Draw dashed join only of a Piece_P3. +dashJOnly_P3 :: OKBackend b => Piece_P3 -> Diagram b+dashJOnly_P3 p = joinDashing (strokeLine $ fromOffsets [joinVector_P3 p])++-- |Draws all edges of a Piece_P3 using a faint dashed line for the join edge+-- (J for plain dashed Join, j for faint dashed join)+drawjPiece_P3 :: OKBackend b => Piece_P3 -> Diagram b+drawjPiece_P3 = drawPiece_P3 <> lw ultraThin . dashJOnly_P3++-- |Draws all edges of a Piece_P3 using a dashed line for the join edge+-- (J for plain dashed Join, j for faint dashed join)+drawJPiece_P3 :: OKBackend b => Piece_P3 -> Diagram b+drawJPiece_P3 = drawPiece_P3 <> dashJOnly_P3++-- |Fills a Piece_P3 with a colour (without drawn edges)+fillOnlyPiece_P3 :: (OKBackend b, Color c) =>+                   c -> Piece_P3 -> Diagram b+fillOnlyPiece_P3 c p = +    lw none $ fillColor c $ +    strokeLoop $ closeLine $ fromOffsets $ drawnEdges_P3 p++-- |Fills a Piece_P3 with one of 2 colours (but no drawn edges).+-- The first colour is used for wide rhombuses, and the second for narrow rhombuses.+-- (Note the order WN)+fillOnlyPieceWN :: (OKBackend b, Color cw, Color cn) =>+               cw -> cn -> Piece_P3 -> Diagram b+fillOnlyPieceWN cw cn rp = filledpiece where+    filledpiece = case rp of+        (LW _ ) -> fillOnlyPiece_P3 cw rp+        (RW _ ) -> fillOnlyPiece_P3 cw rp+        _       -> fillOnlyPiece_P3 cn rp++-- |Fills and draws a Piece_P3 with one of 2 colours+-- The first colour is used for wide rhombuses, and the second for narrow rhombuses.+-- (Note the order WN)+fillPieceWN :: (OKBackend b, Color cw, Color cn) =>+               cw -> cn -> Piece_P3 -> Diagram b+fillPieceWN cw cn = drawPiece_P3 <> fillOnlyPieceWN cw cn+++-- | A class for things that can be turned to diagrams when given a function to draw Piece_P3s.+class Drawable_P3 a where+  drawWith_P3 :: OKBackend b =>+                (Piece_P3 ->  Diagram b) -> a -> Diagram b++-- | Tgraph_P3 can be drawn (as faces_P3)+instance Drawable_P3 Tgraph_P3 where+  -- | turn a Tgraph_P3 into a diagram given a function for drawing P3_Pieces.+  drawWith_P3 :: OKBackend b => (Piece_P3 -> Diagram b) -> Tgraph_P3 -> Diagram b+  drawWith_P3 pd = drawWith_P3 pd . makeVP_P3++-- | VPatch_P3 can be drawn (as rhombuses)+instance Drawable_P3 VPatch_P3 where+  -- | turn a VPatch_P3 into a diagram given a function for drawing P3_Pieces.+  drawWith_P3 :: OKBackend b => (Piece_P3 -> Diagram b) -> VPatch_P3 -> Diagram b+  drawWith_P3 pd = drawWith_P3 pd . dropLabels_P3++-- | A Patch_P3 is Drawable_P3.+instance Drawable_P3 Patch_P3 where+  -- | turn a Patch_P3 into a diagram given a function for drawing Piece_P3s.+  drawWith_P3 :: OKBackend b => (Piece_P3 -> Diagram b) -> Patch_P3 -> Diagram b+  drawWith_P3 pd = position . fmap (viewLoc . mapLoc pd)++-- | A Tgraph is Drawable_P3.+instance Drawable_P3 Tgraph where+    drawWith_P3 :: OKBackend b => (Piece_P3 -> Diagram b) -> Tgraph -> Diagram b+    drawWith_P3 pd = drawWith_P3 pd . makeVP++-- | A VPatch is Drawable_P3.+instance Drawable_P3 VPatch where+    drawWith_P3 :: OKBackend b => (Piece_P3 -> Diagram b) -> VPatch -> Diagram b+    drawWith_P3 pd = drawWith_P3 pd . dropLabels++-- | A Patch is also Drawable_P3 (by conversion to a Patch_P3).+instance Drawable_P3 Patch where+  drawWith_P3 :: OKBackend b => (Piece_P3 -> Diagram b) -> Patch -> Diagram b+  drawWith_P3 pd = drawWith_P3 pd . decompPatchP2toP3++-- |The main drawing function for anything Drawable_P3+draw_P3 :: (OKBackend b, Drawable_P3 a) => +          a -> Diagram b+draw_P3 = drawWith_P3 drawPiece_P3++-- |An alternative drawing function for anything Drawable_P3 adding faint dashed lines for join edges+-- (J for plain dashed Join, j for faint dashed join)+drawj_P3 :: (OKBackend b, Drawable_P3 a) => +          a -> Diagram b+drawj_P3 = drawWith_P3 drawjPiece_P3++-- |An alternative drawing function for anything Drawable_P3 adding dashed lines for join edges+-- (J for plain dashed Join, j for faint dashed join)+drawJ_P3 :: (OKBackend b, Drawable_P3 a) => +          a -> Diagram b+drawJ_P3 = drawWith_P3 drawJPiece_P3++-- |The main draw and fill function for anything Drawable_P3.+-- The first colour is used for wide rhombuses, and the second for narrow rhombuses.+-- (Note the order W N).+fillWN :: (OKBackend b, Drawable_P3 a, Color cw, Color cn) =>+          cw -> cn -> a -> Diagram b+fillWN cw cn = drawWith_P3 (fillPieceWN cw cn)++-- |A variation on fillWN where+-- the first colour is for narrow rhombuses, the second for wide rhombuses.+-- (Note the order N W).+fillNW :: (OKBackend b, Drawable_P3 a, Color cw, Color cn) =>+          cw -> cn -> a -> Diagram b+fillNW = flip fillWN --drawWith_P3 (fillPieceWN cw cn)+++-- | A class for things that can be drawn (P3 style) with labels when given a colour and a measure (size) for the labels and a +-- a draw function (for Patch_P3es).+-- So labelColourSize_P3 c m  modifies a Patch_P3 drawing function to add labels (of colour c and size measure m).+-- Measures are defined in Diagrams. In particular: tiny, verySmall, small, normal, large, veryLarge, huge.+class DrawableLabelled_P3 a where+   labelColourSize_P3 :: OKBackend b => +                        Colour Double -> Measure Double -> (Patch_P3 -> Diagram b) -> a -> Diagram b++-- | Tgraph_P3 can be drawn with labels (as faces_P3)+instance DrawableLabelled_P3 Tgraph_P3 where+  labelColourSize_P3 c m d = labelColourSize_P3 c m d . makeVP_P3++-- | VPatch_P3 can be drawn with labels (as rhombuses)+instance DrawableLabelled_P3 VPatch_P3 where+  labelColourSize_P3 c m d vp3 = drawLabels <> d (dropLabels_P3 vp3) where+     drawLabels = position $ drawlabel <$> VMap.toList (vLocs_P3 vp3)+     drawlabel(v,p) = (p, baselineText (show v) # fontSize m # fc c)++-- | Tgraphs can be drawn (Rhombus/P3 style) with labels+-- Thus using such a vertex for alignment will raise an error.+instance DrawableLabelled_P3 Tgraph where+     labelColourSize_P3 c m d = labelColourSize_P3 c m d . decomposeToRhombuses --makeVP++-- | VPatches can be drawn (Rhombus/P3 style) with labels+-- NB: the additional vertices for P3 are only added when drawing and are not part of the VPatch.+-- Thus using such a vertex for alignment will raise an error.+instance DrawableLabelled_P3 VPatch where+     labelColourSize_P3 c m d vp = drawLabels <> d p3Patch where+        p3Patch = decompPatchP2toP3 $ dropLabels vp+        drawLabels = position $ drawlabel <$> VMap.toList (extendLocs_P3 vp)+        drawlabel(v,p) = (p, baselineText (show v) # fontSize m # fc c)++-- | (Not exported) Extend the vertex locations of a VPatch with locations for new kite join vertices+-- appearing in (Rhombus/P3 style) drawing of tiles.+-- The new vertex numbers are generated with phiVMap from Tgraph.Decompose+extendLocs_P3 :: VPatch -> VertexLocMap+extendLocs_P3 vp = locmap <> VMap.fromList (map (locateNew . joinOfTile) (kites vp)) where+    locmap = vLocs vp+    newemap = phiVMap vp+    locateNew (a,b) = case (VMap.lookup a locmap, VMap.lookup b locmap) of+        (Just pa, Just pb) -> (newemap Map.! (a,b), pa .+^ (phi-1) *^ (pb .-. pa))+        _ -> error "extendLocs_P3: Missing location for a kite join"+++-- | Default Version of labelColourSize_P3 with colour red.+-- Example usage: labelSize_P3 tiny draw_P3 a , labelSize_P3 normal drawj_P3 a+labelSize_P3 :: (OKBackend b, DrawableLabelled_P3 a) =>+               Measure Double -> (Patch_P3 -> Diagram b) -> a -> Diagram b+labelSize_P3 = labelColourSize_P3 red++-- | Default Version of labelColourSize_P3 using red and small (rather than normal label size).+-- Example usage: labelled_P3 draw_P3 a , labelled_P3 drawj_P3 a+labelled_P3 :: (OKBackend b, DrawableLabelled_P3 a) =>+            (Patch_P3 -> Diagram b) -> a -> Diagram b+labelled_P3 = labelColourSize_P3 red small --(normalized 0.023)
src/TgraphExamples.hs view
@@ -97,6 +97,7 @@  , extendChoicesFig      -- * Example showing a P3 tiling  , testRhombus+ , composeToRhombusProblem       -- * Examples showing VPatch transform and deform  , testVPTransform  , deformExample@@ -528,8 +529,9 @@                   lw ultraThin (aligning (1,5) draw d)  --- | An example to illustrate drawing P3 tiling (rhombuses).--- The top part (filled) is a 5 times decomposed sunGraph converted to rhombuses (P3) when drawn.+-- | An example to illustrate drawing a Tgraph as a P3 tiling (rhombuses).+-- The top part (filled) is a 5 times decomposed sunGraph which is+-- converted to rhombuses (P3) when drawn. -- The bottom part is the 5 times decomposed sunGraph reflected about its x-axis. testRhombus :: OKBackend b => Diagram b testRhombus = padBorder $ lw veryThin $@@ -537,6 +539,16 @@               ===               draw g # reflectY       where g = decompositions sunGraph !! 5++-- |This example shows that force sun3Dart (left), when composed to rhombuses (right),+-- has a crossing boundary. The lime coloured faces are (remainder) half kites+-- not included in the composition.+composeToRhombusProblem :: OKBackend b => Diagram b+composeToRhombusProblem = padBorder $ lw thin $ hsep 0.5 [draw vp, fillWN grey lightgray vp3 <> lc lime (draw vp)]+   where g = force sun3Dart+         vp =  alignedVP (1,4) g+         vp3 = convertVPatch rhom vp+         rhom = runTry $ tryComposeToFaces_P3 g  -- |Performs a shearY transform before and after drawing a forced queenGraph with labels. -- The left figure shows an untransformed forced queenGraph.
− src/TileLibP3.hs
@@ -1,337 +0,0 @@-{-|-Module      : TileLibP3-Description : Converting between Kites and Darts (P2 tiles) to Rhombuses (P3 tiles) and drawing-Copyright   : (c) Chris Reade, 2021-License     : BSD-style-Maintainer  : chrisreade@mac.com-Stability   : experimental--This module introduces Penrose\'s P3 tilings (narrow and wide rhombuses).-It includes P3_HalfTiles, P3_Pieces and P3_Patches to represent and draw-rhombuses plus conversion to and from Darts and Kites (the P2 tiles).-A class P3_Drawable is introduced with instance P3_Patch, Patch, VPatch, Tgraph-and generalised drawing functions for drawing P3 tilings.--}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE FlexibleContexts          #-}-{-# LANGUAGE TypeFamilies              #-}-{-# LANGUAGE FlexibleInstances         #-} -- needed for P3_Drawable P3_Patch-{-# LANGUAGE Strict                    #-}--- {-# LANGUAGE TypeOperators             #-} -- needed for type equality constraints ~--module TileLibP3 -  ( -  -- * P3_HalfTiles-    P3_HalfTile(..)- -- , tileRepP3-  , joinVectorP3-  , drawnEdgesP3-  -- * P3_Pieces-  , P3_Piece-  -- * Converting (located) Pieces-  , decompPieceP2toP3-  , decompPieceP3toP2-  -- * Converting Patches-  , P3_Patch-  , decompP2toP3-  , decompP3toP2-  -- * Drawing P3_Pieces-  , drawPieceP3-  , drawjPieceP3-  , drawJPieceP3-  , fillOnlyPieceP3-  , fillOnlyPieceWN-  , fillPieceWN-   -- * P3_Drawable Class-  , P3_Drawable(..)-  -- * Drawing functions producing P3 Rhombuses-  , drawP3-  , drawjP3-  , drawJP3-  , fillWN-  , fillNW-  -- * P3_DrawableLabelled Class-  , P3_DrawableLabelled(..)-  -- * Adding labels to functions producing P3 Rhombuses-  , labelSizeP3-  , labelledP3-  ) where--import Diagrams.Prelude---import Diagrams.TwoD.Text (Text) -- now in CheckBackend--import CheckBackend-import HalfTile-import TileLib-import Tgraph.Prelude-import Tgraph.Decompose ( phiVMap )--import qualified Data.Map.Strict as Map ((!))-import qualified Data.IntMap.Strict as VMap (fromList, toList, lookup)----- | Penrose P3 Tiling uses wide and narrow rhombuses--- These are split into half tiles (triangles) as with kites and darts-data P3_HalfTile a-   = LW a -- ^ Left Wide Rhombus-   | RW a -- ^ Right Wide Rhombus-   | LN a -- ^ Left Narrow Rhombus-   | RN a -- ^ Right Narrow Rhombus-   deriving (Show,Eq)--{-# INLINE tileRepP3 #-}--- | tileRepP3 produces the representation without the label (LW,RW,LN,RN)-tileRepP3 :: P3_HalfTile a -> a-tileRepP3 (LW a) = a-tileRepP3 (RW a) = a-tileRepP3 (LN a) = a-tileRepP3 (RN a) = a---- |Needed for Transformable instance of P3_HalfTile - requires TypeFamilies-type instance N (P3_HalfTile a) = N a--- |Needed for Transformable instance of P3_HalfTile - requires TypeFamilies-type instance V (P3_HalfTile a) = V a--- |P3_HalfTile inherits Transformable  - Requires FlexibleInstances-instance Transformable a => Transformable (P3_HalfTile a) where-    transform t = fmap (transform t)---- |A P3_Piece is a P3_Halftile with a list of two vectors for the drawn edges.--- The join vector for a wide rhombus is on the long diagonal,--- and the join vector for a narrow rhombus is along the short diagonal.--- The choice of which vertex is the origin is derived from conversions--- from Darts and Kites (P2 tilings) -type P3_Piece = P3_HalfTile [V2 Double]---- |The drawn edges of a P3_Piece excluding the join edge (as a list of vectors)--- starting from the origin.-drawnEdgesP3 :: P3_Piece -> [V2 Double]-drawnEdgesP3 = tileRepP3---- |The join edge vector of a P3_Piece (from origin)-joinVectorP3 :: P3_Piece -> V2 Double-joinVectorP3 = sumV . drawnEdgesP3---- |Make P3_Halftile a Functor-instance Functor P3_HalfTile where-    fmap f (LW rep) = LW (f rep)-    fmap f (RW rep) = RW (f rep)-    fmap f (LN rep) = LN (f rep)-    fmap f (RN rep) = RN (f rep)---- |Converting from P2 to P3 tilings.--- Half darts become half wide rhombuses (LD->RW,RD->LW).--- The rhombus origin is the dart wing, the rhombus opp is the dart origin, so--- the rhombus join is the dart long edge.--- Half kites are decomposed to a half wide and a half narrow rhombus--- (LK -> RW and RN, RK -> LW and LN).--- For wide rhombuses, the origin is the kite origin and rhombus opp is the kite wing--- (the join is the kite long edge).--- For narrow rhombuses, the origin is the kite opp and the rhombus wing is the kite opp--- (the join is toward the kite origin.)-decompPieceP2toP3 :: Located Piece -> [Located P3_Piece]-decompPieceP2toP3 lp = case viewLoc lp of-    (p, LK [z1,z2]) -> [ RW [s1, s2] `at` p-                       , RN [negate z2, negate s2] `at` p.+^j-                       ]-        where j = sumV [z1,z2]-              s1 = (phi-1) *^ j-              s2 = z1 ^-^ s1-    (p, RK [z1,z2]) -> [ LW [s1, s2] `at` p-                       , LN [negate z2, negate s2] `at` p.+^j-                       ]-        where j = sumV [z1,z2]-              s1 = (phi-1) *^ j-              s2 = z1 ^-^ s1-    (p, LD [z1,z2]) -> [ RW [z2,s1] `at` p.+^ z1]-        where s1 = negate (sumV [z1,z2])-    (p, RD [z1,z2]) -> [ LW [z2,s1] `at` p.+^ z1]-        where s1 = negate (sumV [z1,z2])-    other -> error $ "decompPieceP2toP3: " ++ show other ++ "/n"---- |Converting from P3 to P2 tilings.--- Half narrow rhombuses become half kites (LN->RK,RN->LK).--- The rhombus wing becomes the kite origin and the rhombus origin becomes the kite wing.--- Half wide rhombuses are decomposed to a half dart and a half kite--- (RW -> LD and RK, LW -> RD and LK).--- The wide rhombus origin becomes the dart origin, and the wide rhombus opp becomes the kite origin.--- The wide rhombus wing becomes both the kite opp and dart wing.-decompPieceP3toP2 :: Located P3_Piece -> [Located Piece]-decompPieceP3toP2 lp = case viewLoc lp of-    (p, LW [z1,z2]) -> -        [ RD [z1,s] `at` p-        , LK [ (1-phi)*^j, negate s] `at` (p.+^j)-        ] where j = sumV [z1,z2]-                s = (2-phi) *^ j ^-^ z1-    (p, RW [z1,z2]) -> -        [ LD [z1,s] `at` p-        , RK [ (1-phi)*^j, negate s] `at` (p.+^j)-        ] where j  = sumV [z1,z2]-                s = (2-phi) *^ j ^-^ z1-    (p, LN [z1,z2]) -> [ RK [negate z1, sumV [z1,z2]] `at` p .+^ z1]-    (p, RN [z1,z2]) -> [ LK [negate z1, sumV [z1,z2]] `at` p .+^ z1]-    other -> error $ "decompPieceP3toP2: " ++ show other ++ "/n"----- | a P3_Patch is analagous to a Patch (but for for P3_Pieces)-type P3_Patch =  [Located P3_Piece]---- |Conversion from a Patch to a P3_Patch (Kites and Darts to Rhombuses)-decompP2toP3 :: Patch -> P3_Patch-decompP2toP3 = concatMap decompPieceP2toP3---- |Conversion from a P3_Patch to a Patch (Rhombuses to Kites and Darts)--- Note this does not reverse decompP2toP3, but the combination--- decompP3toP2 . decompP2toP3 is equivalent to a decompose operation (decompPatch)-decompP3toP2 :: P3_Patch -> Patch-decompP3toP2 = concatMap decompPieceP3toP2----- |Draws the two drawn edges of a P3_Piece-drawPieceP3 :: OKBackend b => P3_Piece -> Diagram b-drawPieceP3 = strokeLine . fromOffsets . drawnEdgesP3----- |Draw dashed join only of a P3_Piece. -dashJOnlyP3 :: OKBackend b => P3_Piece -> Diagram b-dashJOnlyP3 p = joinDashing (strokeLine $ fromOffsets [joinVectorP3 p])---- |Draws all edges of a P3_Piece using a faint dashed line for the join edge--- (J for plain dashed Join, j for faint dashed join)-drawjPieceP3 :: OKBackend b => P3_Piece -> Diagram b-drawjPieceP3 = drawPieceP3 <> lw ultraThin . dashJOnlyP3---- |Draws all edges of a P3_Piece using a dashed line for the join edge--- (J for plain dashed Join, j for faint dashed join)-drawJPieceP3 :: OKBackend b => P3_Piece -> Diagram b-drawJPieceP3 = drawPieceP3 <> dashJOnlyP3---- |Fills a P3_Piece with a colour (without drawn edges)-fillOnlyPieceP3 :: (OKBackend b, Color c) =>-                   c -> P3_Piece -> Diagram b-fillOnlyPieceP3 c p = -    lw none $ fillColor c $ -    strokeLoop $ closeLine $ fromOffsets $ drawnEdgesP3 p---- |Fills a P3_Piece with one of 2 colours (but no drawn edges).--- The first colour is used for wide rhombuses, and the second for narrow rhombuses.--- (Note the order WN)-fillOnlyPieceWN :: (OKBackend b, Color cw, Color cn) =>-               cw -> cn -> P3_Piece -> Diagram b-fillOnlyPieceWN cw cn rp = filledpiece where-    filledpiece = case rp of-        (LW _ ) -> fillOnlyPieceP3 cw rp-        (RW _ ) -> fillOnlyPieceP3 cw rp-        _       -> fillOnlyPieceP3 cn rp---- |Fills and draws a P3_Piece with one of 2 colours--- The first colour is used for wide rhombuses, and the second for narrow rhombuses.--- (Note the order WN)-fillPieceWN :: (OKBackend b, Color cw, Color cn) =>-               cw -> cn -> P3_Piece -> Diagram b-fillPieceWN cw cn = drawPieceP3 <> fillOnlyPieceWN cw cn----- | A class for things that can be turned to diagrams when given a function to draw P3_Pieces.-class P3_Drawable a where-  drawP3With :: OKBackend b =>-                (P3_Piece ->  Diagram b) -> a -> Diagram b---- | A P3_Patch is P3_Drawable.-instance P3_Drawable P3_Patch where-  -- | turn a P3_Patch into a diagram given a function for drawing P3_Pieces.-  drawP3With :: OKBackend b => (P3_Piece -> Diagram b) -> P3_Patch -> Diagram b-  drawP3With pd = position . fmap (viewLoc . mapLoc pd)---- | A Patch is also P3_Drawable (by conversion to a P3_Patch).-instance P3_Drawable Patch where-  drawP3With :: OKBackend b => (P3_Piece -> Diagram b) -> Patch -> Diagram b-  drawP3With pd = drawP3With pd . decompP2toP3---- | A VPatch is P3_Drawable.-instance P3_Drawable VPatch where-    drawP3With :: OKBackend b => (P3_Piece -> Diagram b) -> VPatch -> Diagram b-    drawP3With pd = drawP3With pd . dropLabels---- | A Tgraph is P3_Drawable.-instance P3_Drawable Tgraph where-    drawP3With :: OKBackend b => (P3_Piece -> Diagram b) -> Tgraph -> Diagram b-    drawP3With pd = drawP3With pd . makeVP---- |The main drawing function for anything P3_Drawable-drawP3 :: (OKBackend b, P3_Drawable a) => -          a -> Diagram b-drawP3 = drawP3With drawPieceP3---- |An alternative drawing function for anything P3_Drawable adding faint dashed lines for join edges--- (J for plain dashed Join, j for faint dashed join)-drawjP3 :: (OKBackend b, P3_Drawable a) => -          a -> Diagram b-drawjP3 = drawP3With drawjPieceP3---- |An alternative drawing function for anything P3_Drawable adding dashed lines for join edges--- (J for plain dashed Join, j for faint dashed join)-drawJP3 :: (OKBackend b, P3_Drawable a) => -          a -> Diagram b-drawJP3 = drawP3With drawJPieceP3---- |The main draw and fill function for anything P3_Drawable.--- The first colour is used for wide rhombuses, and the second for narrow rhombuses.--- (Note the order W N).-fillWN :: (OKBackend b, P3_Drawable a, Color cw, Color cn) =>-          cw -> cn -> a -> Diagram b-fillWN cw cn = drawP3With (fillPieceWN cw cn)---- |A variation on fillWN where--- the first colour is for narrow rhombuses, the second for wide rhombuses.--- (Note the order N W).-fillNW :: (OKBackend b, P3_Drawable a, Color cw, Color cn) =>-          cw -> cn -> a -> Diagram b-fillNW = flip fillWN --drawP3With (fillPieceWN cw cn)----- | A class for things that can be drawn (P3 style) with labels when given a colour and a measure (size) for the labels and a --- a draw function (for P3_Patches).--- So labelColourSizeP3 c m  modifies a P3_Patch drawing function to add labels (of colour c and size measure m).--- Measures are defined in Diagrams. In particular: tiny, verySmall, small, normal, large, veryLarge, huge.-class P3_DrawableLabelled a where-   labelColourSizeP3 :: OKBackend b => -                        Colour Double -> Measure Double -> (P3_Patch -> Diagram b) -> a -> Diagram b---- | VPatches can be drawn (Rhombus/P3 style) with labels--- NB: the additional vertices for P3 are only added when drawing and are not part of the VPatch.--- Thus using such a vertex for alignment will raise an error.-instance P3_DrawableLabelled VPatch where-     labelColourSizeP3 c m d vp = drawLabels <> d p3Patch where-        p3Patch = decompP2toP3 $ dropLabels vp-        drawLabels = position $ drawlabel <$> VMap.toList (extendLocsP3 vp)-        drawlabel(v,p) = (p, baselineText (show v) # fontSize m # fc c)---- | (Not exported) Extend the vertex locations of a VPatch with locations for new kite join vertices--- appearing in (Rhombus/P3 style) drawing of tiles.--- The new vertex numbers are generated with phiVMap from Tgraph.Decompose-extendLocsP3 :: VPatch -> VertexLocMap-extendLocsP3 vp = locmap <> VMap.fromList (map (locateNew . joinOfTile) (kites vp)) where-    locmap = vLocs vp-    newemap = phiVMap vp-    locateNew (a,b) = case (VMap.lookup a locmap, VMap.lookup b locmap) of-        (Just pa, Just pb) -> (newemap Map.! (a,b), pa .+^ (phi-1) *^ (pb .-. pa))-        _ -> error "extendLocsP3: Missing location for a kite join"---- | Tgraphs can be drawn (Rhombus/P3 style) with labels--- NB: the additional vertices for P3 are only added when drawing and are not part of the Tgraph--- or its VPatch.--- Thus using such a vertex for alignment will raise an error.-instance P3_DrawableLabelled Tgraph where-     labelColourSizeP3 c m d = labelColourSizeP3 c m d . makeVP---- | Default Version of labelColourSizeP3 with colour red.--- Example usage: labelSizeP3 tiny drawP3 a , labelSizeP3 normal drawjP3 a-labelSizeP3 :: (OKBackend b, P3_DrawableLabelled a) =>-               Measure Double -> (P3_Patch -> Diagram b) -> a -> Diagram b-labelSizeP3 = labelColourSizeP3 red---- | Default Version of labelColourSizeP3 using red and small (rather than normal label size).--- Example usage: labelledP3 drawP3 a , labelledP3 drawjP3 a-labelledP3 :: (OKBackend b, P3_DrawableLabelled a) =>-            (P3_Patch -> Diagram b) -> a -> Diagram b-labelledP3 = labelColourSizeP3 red small --(normalized 0.023)