packages feed

wumpus-drawing 0.1.0 → 0.2.0

raw patch · 46 files changed

+3512/−1350 lines, 46 filesdep −directorydep −filepathdep ~wumpus-basicdep ~wumpus-corePVP ok

version bump matches the API change (PVP)

Dependencies removed: directory, filepath

Dependency ranges changed: wumpus-basic, wumpus-core

API changes (from Hackage documentation)

- Wumpus.Drawing.Chains.Base: type Chain u = [Point2 u]
- Wumpus.Drawing.Chains.Base: unchainTD :: Int -> (Point2 u -> TraceDrawing u ()) -> Chain u -> TraceDrawing u ()
- Wumpus.Drawing.Chains.Base: zipchain :: [LocGraphic u] -> Chain u -> TraceDrawing u ()
- Wumpus.Drawing.Chains.Base: zipchainTD :: [Point2 u -> TraceDrawing u ()] -> Chain u -> TraceDrawing u ()
- Wumpus.Drawing.Chains.Base: zipchainWith :: (a -> LocGraphic u) -> [a] -> Chain u -> TraceDrawing u ()
- Wumpus.Drawing.Chains.Base: zipchainWithTD :: (a -> Point2 u -> TraceDrawing u ()) -> [a] -> Chain u -> TraceDrawing u ()
- Wumpus.Drawing.Chains.Derived: horizontal :: Num u => u -> LocChain u
- Wumpus.Drawing.Chains.Derived: horizontals :: Num u => [u] -> LocChain u
- Wumpus.Drawing.Chains.Derived: vertical :: Num u => u -> LocChain u
- Wumpus.Drawing.Chains.Derived: verticals :: Num u => [u] -> LocChain u
- Wumpus.Drawing.Dots.AnchorDots: instance Eq Cardinal
- Wumpus.Drawing.Dots.AnchorDots: instance Show Cardinal
- Wumpus.Drawing.Geometry.Intersection: LS :: (Point2 u) -> (Point2 u) -> LineSegment u
- Wumpus.Drawing.Geometry.Intersection: data LineEqn u
- Wumpus.Drawing.Geometry.Intersection: data LineSegment u
- Wumpus.Drawing.Geometry.Intersection: data PointSlope u
- Wumpus.Drawing.Geometry.Intersection: findIntersect :: (Floating u, Real u, Ord u) => Point2 u -> Radian -> [LineSegment u] -> Maybe (Point2 u)
- Wumpus.Drawing.Geometry.Intersection: instance Eq u => Eq (IntersectionResult u)
- Wumpus.Drawing.Geometry.Intersection: instance Eq u => Eq (LineEqn u)
- Wumpus.Drawing.Geometry.Intersection: instance Eq u => Eq (LineSegment u)
- Wumpus.Drawing.Geometry.Intersection: instance Eq u => Eq (PointSlope u)
- Wumpus.Drawing.Geometry.Intersection: instance Ord u => Ord (LineSegment u)
- Wumpus.Drawing.Geometry.Intersection: instance Show u => Show (IntersectionResult u)
- Wumpus.Drawing.Geometry.Intersection: instance Show u => Show (LineEqn u)
- Wumpus.Drawing.Geometry.Intersection: instance Show u => Show (LineSegment u)
- Wumpus.Drawing.Geometry.Intersection: instance Show u => Show (PointSlope u)
- Wumpus.Drawing.Geometry.Intersection: intersection :: (Fractional u, Ord u) => LineSegment u -> LineEqn u -> Maybe (Point2 u)
- Wumpus.Drawing.Geometry.Intersection: langle :: (Floating u, Real u) => Point2 u -> Point2 u -> Radian
- Wumpus.Drawing.Geometry.Intersection: lineEqn :: Num u => Point2 u -> Point2 u -> LineEqn u
- Wumpus.Drawing.Geometry.Intersection: pointSlope :: Fractional u => Point2 u -> Radian -> PointSlope u
- Wumpus.Drawing.Geometry.Intersection: polygonLines :: [Point2 u] -> [LineSegment u]
- Wumpus.Drawing.Geometry.Intersection: rectangleLines :: Num u => Point2 u -> u -> u -> [LineSegment u]
- Wumpus.Drawing.Geometry.Intersection: toLineEqn :: Num u => PointSlope u -> LineEqn u
- Wumpus.Drawing.Geometry.Paths: coordinatePrimPath :: Num u => Point2 u -> LocCoordPath u -> PrimPath u
- Wumpus.Drawing.Geometry.Paths: diamondCoordPath :: Num u => u -> u -> LocCoordPath u
- Wumpus.Drawing.Geometry.Paths: equilateralTriangleCoordPath :: Floating u => u -> LocCoordPath u
- Wumpus.Drawing.Geometry.Paths: equilateralTrianglePoints :: Floating u => u -> Point2 u -> (Point2 u, Point2 u, Point2 u)
- Wumpus.Drawing.Geometry.Paths: isoscelesTriangleCoordPath :: Floating u => u -> u -> LocCoordPath u
- Wumpus.Drawing.Geometry.Paths: isoscelesTrianglePoints :: Floating u => u -> u -> Point2 u -> (Point2 u, Point2 u, Point2 u)
- Wumpus.Drawing.Geometry.Paths: polygonCoordPath :: Floating u => Int -> u -> LocCoordPath u
- Wumpus.Drawing.Geometry.Paths: rectangleCoordPath :: Num u => u -> u -> LocCoordPath u
- Wumpus.Drawing.Geometry.Paths: type LocCoordPath u = Point2 u -> [Point2 u]
- Wumpus.Drawing.Shapes.Base: intoLocShape :: LocCF u a -> LocCF u (Path u) -> LocCF u (a, Path u)
- Wumpus.Drawing.Shapes.Base: projectPoint :: (Real u, Floating u) => Point2 u -> ShapeCTM u -> Point2 u
- Wumpus.Drawing.Shapes.Base: type LocShape u a = LocCF u (a, Path u)
- Wumpus.Drawing.Shapes.Circle: instance Eq u => Eq (Circle u)
- Wumpus.Drawing.Shapes.Circle: instance Show u => Show (Circle u)
- Wumpus.Drawing.Text.LRText: baseCenterEscChar :: (Real u, Floating u, FromPtSize u) => EscapedChar -> BoundedLocGraphic u
- Wumpus.Drawing.Text.LRText: baseCenterLine :: (Real u, Floating u, FromPtSize u) => String -> BoundedLocGraphic u
- Wumpus.Drawing.Text.LRText: baseLeftLine :: (Real u, Floating u, FromPtSize u) => String -> BoundedLocGraphic u
- Wumpus.Drawing.Text.LRText: baseRightLine :: (Real u, Floating u, FromPtSize u) => String -> BoundedLocGraphic u
- Wumpus.Drawing.Text.LRText: ctrCenterLine :: (Real u, Floating u, FromPtSize u) => String -> BoundedLocGraphic u
- Wumpus.Drawing.Text.LRText: rbaseCenterLine :: (Real u, Floating u, FromPtSize u) => String -> BoundedLocThetaGraphic u
- Wumpus.Drawing.Text.LRText: rbaseLeftLine :: (Real u, Floating u, FromPtSize u) => String -> BoundedLocThetaGraphic u
- Wumpus.Drawing.Text.LRText: rbaseRightLine :: (Real u, Floating u, FromPtSize u) => String -> BoundedLocThetaGraphic u
- Wumpus.Drawing.Text.LRText: rmultiAlignCenter :: (Floating u, Real u, Ord u, FromPtSize u) => String -> BoundedLocThetaGraphic u
- Wumpus.Drawing.Text.LRText: rmultiAlignLeft :: (Floating u, Real u, Ord u, FromPtSize u) => String -> BoundedLocThetaGraphic u
- Wumpus.Drawing.Text.LRText: rmultiAlignRight :: (Floating u, Real u, Ord u, FromPtSize u) => String -> BoundedLocThetaGraphic u
+ Wumpus.Drawing.Chains.Base: liftChainF :: (Point2 u -> PointChain u) -> LocChain u
+ Wumpus.Drawing.Chains.Base: type ConnectorChain u = ConnectorCF u (PointChain u)
+ Wumpus.Drawing.Chains.Base: type PointChain u = [Point2 u]
+ Wumpus.Drawing.Chains.Base: unchainU :: (Num u, OPlus a) => LocCF u (ImageAns u a) -> LocCF u (ImageAns u a) -> LocChain u -> LocCF u (ImageAns u a)
+ Wumpus.Drawing.Chains.Base: unchainZip :: (Num u, OPlus a) => LocCF u (ImageAns u a) -> [LocCF u (ImageAns u a)] -> LocChain u -> LocCF u (ImageAns u a)
+ Wumpus.Drawing.Chains.Base: unchainZipWith :: (Num u, OPlus a) => LocCF u (ImageAns u a) -> (s -> LocCF u (ImageAns u a)) -> [s] -> LocChain u -> LocCF u (ImageAns u a)
+ Wumpus.Drawing.Chains.Base: unconnectorChain :: (Num u, OPlus a) => ConnectorCF u (ImageAns u a) -> LocCF u (ImageAns u a) -> ConnectorChain u -> ConnectorCF u (ImageAns u a)
+ Wumpus.Drawing.Chains.Derived: horizontalPoints :: Num u => u -> LocChain u
+ Wumpus.Drawing.Chains.Derived: horizontalSteps :: Num u => [u] -> LocChain u
+ Wumpus.Drawing.Chains.Derived: innerHorizontals :: RealFrac u => u -> ConnectorChain u
+ Wumpus.Drawing.Chains.Derived: innerVerticals :: RealFrac u => u -> ConnectorChain u
+ Wumpus.Drawing.Chains.Derived: verticalPoints :: Num u => u -> LocChain u
+ Wumpus.Drawing.Chains.Derived: verticalSteps :: Num u => [u] -> LocChain u
+ Wumpus.Drawing.Grids: grid :: Fractional u => (Int, Int) -> u -> LocGraphic u
+ Wumpus.Drawing.Grids: interiorGrid :: RealFrac u => u -> ConnectorGraphic u
+ Wumpus.Drawing.Shapes.Base: data Shape u a
+ Wumpus.Drawing.Shapes.Base: displaceCenter :: (Real u, Floating u) => Vec2 u -> ShapeCTM u -> Point2 u
+ Wumpus.Drawing.Shapes.Base: instance Functor (Shape u)
+ Wumpus.Drawing.Shapes.Base: makeShape :: Num u => LocThetaCF u a -> LocThetaCF u (Path u) -> Shape u a
+ Wumpus.Drawing.Shapes.Base: rborderedShape :: Num u => Shape u a -> LocThetaImage u a
+ Wumpus.Drawing.Shapes.Base: rfilledShape :: Num u => Shape u a -> LocThetaImage u a
+ Wumpus.Drawing.Shapes.Base: rstrokedShape :: Num u => Shape u a -> LocThetaImage u a
+ Wumpus.Drawing.Shapes.Base: setDecoration :: LocThetaGraphic u -> Shape u a -> Shape u a
+ Wumpus.Drawing.Shapes.Base: type DShape a = Shape Double a
+ Wumpus.Drawing.Shapes.Base: updatePathAngle :: (Radian -> Radian) -> Shape u a -> Shape u a
+ Wumpus.Drawing.Shapes.Diamond: instance (Real u, Floating u) => ApexAnchor (Diamond u)
+ Wumpus.Drawing.Shapes.Diamond: instance (Real u, Floating u) => SideMidpointAnchor (Diamond u)
+ Wumpus.Drawing.Shapes.InvSemicircle: data InvSemicircle u
+ Wumpus.Drawing.Shapes.InvSemicircle: instance (Real u, Floating u) => ApexAnchor (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance (Real u, Floating u) => CardinalAnchor (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance (Real u, Floating u) => CenterAnchor (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance (Real u, Floating u) => RotateAbout (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance (Real u, Floating u) => TopCornerAnchor (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor2 (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance (Real u, Floating u, FromPtSize u) => RadialAnchor (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance Num u => Scale (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance Num u => Translate (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: instance Rotate (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: invsemicircle :: (Real u, Floating u, FromPtSize u) => u -> Shape u (InvSemicircle u)
+ Wumpus.Drawing.Shapes.InvSemicircle: type DInvSemicircle = InvSemicircle Double
+ Wumpus.Drawing.Shapes.InvSemiellipse: data InvSemiellipse u
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance (Real u, Floating u) => CenterAnchor (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance (Real u, Floating u) => RotateAbout (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance (Real u, Floating u) => TopCornerAnchor (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance (Real u, Floating u, FromPtSize u) => ApexAnchor (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor2 (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance (Real u, Floating u, FromPtSize u) => RadialAnchor (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance Num u => Scale (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance Num u => Translate (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: instance Rotate (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: invsemiellipse :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (InvSemiellipse u)
+ Wumpus.Drawing.Shapes.InvSemiellipse: type DInvSemiellipse = InvSemiellipse Double
+ Wumpus.Drawing.Shapes.InvTriangle: data InvTriangle u
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => ApexAnchor (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => CardinalAnchor (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => CardinalAnchor2 (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => CenterAnchor (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => RadialAnchor (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => RotateAbout (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => SideMidpointAnchor (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance (Real u, Floating u) => TopCornerAnchor (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance Num u => Scale (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance Num u => Translate (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: instance Rotate (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: invtriangle :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (InvTriangle u)
+ Wumpus.Drawing.Shapes.InvTriangle: type DInvTriangle = InvTriangle Double
+ Wumpus.Drawing.Shapes.Parallelogram: data Parallelogram u
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u) => BottomCornerAnchor (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u) => CardinalAnchor (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u) => CenterAnchor (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u) => RotateAbout (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u) => SideMidpointAnchor (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u) => TopCornerAnchor (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor2 (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance (Real u, Floating u, FromPtSize u) => RadialAnchor (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance Num u => Scale (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance Num u => Translate (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: instance Rotate (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: parallelogram :: (Real u, Floating u, FromPtSize u) => u -> u -> Radian -> Shape u (Parallelogram u)
+ Wumpus.Drawing.Shapes.Parallelogram: type DParallelogram = Parallelogram Double
+ Wumpus.Drawing.Shapes.Parallelogram: zparallelogram :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (Parallelogram u)
+ Wumpus.Drawing.Shapes.Rectangle: instance (Real u, Floating u) => BottomCornerAnchor (Rectangle u)
+ Wumpus.Drawing.Shapes.Rectangle: instance (Real u, Floating u) => SideMidpointAnchor (Rectangle u)
+ Wumpus.Drawing.Shapes.Rectangle: instance (Real u, Floating u) => TopCornerAnchor (Rectangle u)
+ Wumpus.Drawing.Shapes.Semicircle: data Semicircle u
+ Wumpus.Drawing.Shapes.Semicircle: instance (Real u, Floating u) => ApexAnchor (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance (Real u, Floating u) => BottomCornerAnchor (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance (Real u, Floating u) => CardinalAnchor (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance (Real u, Floating u) => CenterAnchor (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance (Real u, Floating u) => RotateAbout (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor2 (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance (Real u, Floating u, FromPtSize u) => RadialAnchor (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance Num u => Scale (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance Num u => Translate (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: instance Rotate (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: semicircle :: (Real u, Floating u, FromPtSize u) => u -> Shape u (Semicircle u)
+ Wumpus.Drawing.Shapes.Semicircle: type DSemicircle = Semicircle Double
+ Wumpus.Drawing.Shapes.Semiellipse: data Semiellipse u
+ Wumpus.Drawing.Shapes.Semiellipse: instance (Real u, Floating u) => BottomCornerAnchor (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance (Real u, Floating u) => CenterAnchor (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance (Real u, Floating u) => RotateAbout (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance (Real u, Floating u, FromPtSize u) => ApexAnchor (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor2 (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance (Real u, Floating u, FromPtSize u) => RadialAnchor (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance Num u => Scale (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance Num u => Translate (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: instance Rotate (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: semiellipse :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (Semiellipse u)
+ Wumpus.Drawing.Shapes.Semiellipse: type DSemiellipse = Semiellipse Double
+ Wumpus.Drawing.Shapes.Trapezium: data Trapezium u
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u) => BottomCornerAnchor (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u) => CenterAnchor (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u) => RotateAbout (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u) => TopCornerAnchor (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u, FromPtSize u) => CardinalAnchor2 (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u, FromPtSize u) => RadialAnchor (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance (Real u, Floating u, FromPtSize u) => SideMidpointAnchor (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance Num u => Scale (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance Num u => Translate (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: instance Rotate (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: trapezium :: (Real u, Floating u, FromPtSize u) => u -> u -> Radian -> Radian -> Shape u (Trapezium u)
+ Wumpus.Drawing.Shapes.Trapezium: type DTrapezium = Trapezium Double
+ Wumpus.Drawing.Shapes.Trapezium: ztrapezium :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (Trapezium u)
+ Wumpus.Drawing.Shapes.Triangle: data Triangle u
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => ApexAnchor (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => BottomCornerAnchor (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => CardinalAnchor (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => CardinalAnchor2 (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => CenterAnchor (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => RadialAnchor (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => RotateAbout (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance (Real u, Floating u) => SideMidpointAnchor (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance Num u => Scale (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance Num u => Translate (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: instance Rotate (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: triangle :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (Triangle u)
+ Wumpus.Drawing.Shapes.Triangle: type DTriangle = Triangle Double
+ Wumpus.Drawing.Text.Base: advtext :: FromPtSize u => EscapedText -> AdvGraphic u
+ Wumpus.Drawing.Text.Base: borderedTextObjectPos :: (Real u, Floating u, FromPtSize u) => Int -> u -> DrawingInfo (ObjectPos u)
+ Wumpus.Drawing.Text.Base: centerSpinePoints :: Floating u => Int -> Radian -> LocChain u
+ Wumpus.Drawing.Text.Base: centerToBaseline :: (Fractional u, FromPtSize u) => DrawingInfo u
+ Wumpus.Drawing.Text.Base: charVector :: FromPtSize u => EscapedChar -> DrawingInfo (AdvanceVec u)
+ Wumpus.Drawing.Text.Base: multilineHeight :: (Real u, Floating u, FromPtSize u) => Int -> DrawingInfo u
+ Wumpus.Drawing.Text.Base: textObjectPos :: (Real u, Floating u, FromPtSize u) => Int -> u -> DrawingInfo (ObjectPos u)
+ Wumpus.Drawing.Text.Base: textVector :: FromPtSize u => EscapedText -> DrawingInfo (AdvanceVec u)
+ Wumpus.Drawing.Text.CatText: (<+>) :: FromPtSize u => CatText u -> CatText u -> CatText u
+ Wumpus.Drawing.Text.CatText: (<>) :: CatText u -> CatText u -> CatText u
+ Wumpus.Drawing.Text.CatText: blank :: Num u => CatText u
+ Wumpus.Drawing.Text.CatText: centerAlign :: (Real u, FromPtSize u, Floating u) => [CatText u] -> PosImage u (BoundingBox u)
+ Wumpus.Drawing.Text.CatText: data CatText u
+ Wumpus.Drawing.Text.CatText: fontColour :: RGBi -> CatText u -> CatText u
+ Wumpus.Drawing.Text.CatText: leftAlign :: (Real u, FromPtSize u, Floating u) => [CatText u] -> PosImage u (BoundingBox u)
+ Wumpus.Drawing.Text.CatText: rightAlign :: (Real u, FromPtSize u, Floating u) => [CatText u] -> PosImage u (BoundingBox u)
+ Wumpus.Drawing.Text.CatText: space :: FromPtSize u => CatText u
+ Wumpus.Drawing.Text.CatText: string :: FromPtSize u => String -> CatText u
+ Wumpus.Drawing.Text.LRText: escSingleLine :: (Real u, Floating u, FromPtSize u) => EscapedText -> PosImage u (BoundingBox u)
+ Wumpus.Drawing.Text.LRText: rescSingleLine :: (Real u, Floating u, FromPtSize u) => Radian -> EscapedText -> PosImage u (BoundingBox u)
+ Wumpus.Drawing.Text.LRText: rsingleLine :: (Real u, Floating u, FromPtSize u) => Radian -> String -> PosImage u (BoundingBox u)
+ Wumpus.Drawing.Text.LRText: singleLine :: (Real u, Floating u, FromPtSize u) => String -> PosImage u (BoundingBox u)
+ Wumpus.Drawing.Text.LRText: textAlignCenter :: (Real u, Floating u, FromPtSize u) => String -> LocImage u (BoundingBox u)
+ Wumpus.Drawing.Text.LRText: textAlignLeft :: (Real u, Floating u, FromPtSize u) => String -> LocImage u (BoundingBox u)
+ Wumpus.Drawing.Text.LRText: textAlignRight :: (Real u, Floating u, FromPtSize u) => String -> LocImage u (BoundingBox u)
- Wumpus.Drawing.Chains.Base: type LocChain u = Point2 u -> Chain u
+ Wumpus.Drawing.Chains.Base: type LocChain u = LocDrawingInfo u (PointChain u)
- Wumpus.Drawing.Chains.Base: unchain :: Int -> LocGraphic u -> Chain u -> TraceDrawing u ()
+ Wumpus.Drawing.Chains.Base: unchain :: (Num u, OPlus a) => Int -> LocCF u (ImageAns u a) -> LocCF u (ImageAns u a) -> LocChain u -> LocCF u (ImageAns u a)
- Wumpus.Drawing.Paths.Base: curve :: (Floating u, Ord u) => Point2 u -> Point2 u -> Point2 u -> Point2 u -> Path u
+ Wumpus.Drawing.Paths.Base: curve :: (Floating u, Ord u, FromPtSize u) => Point2 u -> Point2 u -> Point2 u -> Point2 u -> Path u
- Wumpus.Drawing.Paths.Base: curveByAngles :: (Floating u, Ord u) => Point2 u -> Radian -> Radian -> Point2 u -> Path u
+ Wumpus.Drawing.Paths.Base: curveByAngles :: (Floating u, Ord u, FromPtSize u) => Point2 u -> Radian -> Radian -> Point2 u -> Path u
- Wumpus.Drawing.Paths.Base: roundInterior :: (Real u, Floating u) => u -> [Point2 u] -> Path u
+ Wumpus.Drawing.Paths.Base: roundInterior :: (Real u, Floating u, FromPtSize u) => u -> [Point2 u] -> Path u
- Wumpus.Drawing.Paths.Base: roundTrail :: (Real u, Floating u) => u -> [Point2 u] -> Path u
+ Wumpus.Drawing.Paths.Base: roundTrail :: (Real u, Floating u, FromPtSize u) => u -> [Point2 u] -> Path u
- Wumpus.Drawing.Paths.Base: traceCurvePoints :: (Floating u, Ord u) => [Point2 u] -> Path u
+ Wumpus.Drawing.Paths.Base: traceCurvePoints :: (Floating u, Ord u, FromPtSize u) => [Point2 u] -> Path u
- Wumpus.Drawing.Paths.Connectors: connIsoscelesCurve :: (Real u, Floating u) => u -> ConnectorPath u
+ Wumpus.Drawing.Paths.Connectors: connIsoscelesCurve :: (Real u, Floating u, FromPtSize u) => u -> ConnectorPath u
- Wumpus.Drawing.Paths.Connectors: connSquareCurve :: (Real u, Floating u) => ConnectorPath u
+ Wumpus.Drawing.Paths.Connectors: connSquareCurve :: (Real u, Floating u, FromPtSize u) => ConnectorPath u
- Wumpus.Drawing.Paths.Connectors: connTrapezoidCurve :: (Real u, Floating u) => u -> u -> ConnectorPath u
+ Wumpus.Drawing.Paths.Connectors: connTrapezoidCurve :: (Real u, Floating u, FromPtSize u) => u -> u -> ConnectorPath u
- Wumpus.Drawing.Paths.Connectors: connUSquareCurve :: (Real u, Floating u) => ConnectorPath u
+ Wumpus.Drawing.Paths.Connectors: connUSquareCurve :: (Real u, Floating u, FromPtSize u) => ConnectorPath u
- Wumpus.Drawing.Paths.Connectors: connUZSquareCurve :: (Real u, Floating u) => ConnectorPath u
+ Wumpus.Drawing.Paths.Connectors: connUZSquareCurve :: (Real u, Floating u, FromPtSize u) => ConnectorPath u
- Wumpus.Drawing.Paths.Connectors: connZSquareCurve :: (Real u, Floating u) => ConnectorPath u
+ Wumpus.Drawing.Paths.Connectors: connZSquareCurve :: (Real u, Floating u, FromPtSize u) => ConnectorPath u
- Wumpus.Drawing.Paths.MonadicConstruction: bezierto :: (Floating u, Ord u) => Point2 u -> Point2 u -> Point2 u -> PathM u ()
+ Wumpus.Drawing.Paths.MonadicConstruction: bezierto :: (Floating u, Ord u, FromPtSize u) => Point2 u -> Point2 u -> Point2 u -> PathM u ()
- Wumpus.Drawing.Paths.MonadicConstruction: curveto :: (Floating u, Ord u) => Radian -> Radian -> Point2 u -> PathM u ()
+ Wumpus.Drawing.Paths.MonadicConstruction: curveto :: (Floating u, Ord u, FromPtSize u) => Radian -> Radian -> Point2 u -> PathM u ()
- Wumpus.Drawing.Shapes.Base: borderedShape :: Num u => LocShape u a -> LocImage u a
+ Wumpus.Drawing.Shapes.Base: borderedShape :: Num u => Shape u a -> LocImage u a
- Wumpus.Drawing.Shapes.Base: filledShape :: Num u => LocShape u a -> LocImage u a
+ Wumpus.Drawing.Shapes.Base: filledShape :: Num u => Shape u a -> LocImage u a
- Wumpus.Drawing.Shapes.Base: makeShapeCTM :: Num u => Point2 u -> ShapeCTM u
+ Wumpus.Drawing.Shapes.Base: makeShapeCTM :: Num u => Point2 u -> Radian -> ShapeCTM u
- Wumpus.Drawing.Shapes.Base: strokedShape :: Num u => LocShape u a -> LocImage u a
+ Wumpus.Drawing.Shapes.Base: strokedShape :: Num u => Shape u a -> LocImage u a
- Wumpus.Drawing.Shapes.Circle: circle :: (Real u, Floating u) => u -> LocShape u (Circle u)
+ Wumpus.Drawing.Shapes.Circle: circle :: (Real u, Floating u, FromPtSize u) => u -> Shape u (Circle u)
- Wumpus.Drawing.Shapes.Diamond: diamond :: (Real u, Floating u, FromPtSize u) => u -> u -> LocShape u (Diamond u)
+ Wumpus.Drawing.Shapes.Diamond: diamond :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (Diamond u)
- Wumpus.Drawing.Shapes.Ellipse: ellipse :: (Floating u, Ord u) => u -> u -> LocShape u (Ellipse u)
+ Wumpus.Drawing.Shapes.Ellipse: ellipse :: (Real u, Floating u, FromPtSize u, Ord u) => u -> u -> Shape u (Ellipse u)
- Wumpus.Drawing.Shapes.Rectangle: rectangle :: (Real u, Floating u, FromPtSize u) => u -> u -> LocShape u (Rectangle u)
+ Wumpus.Drawing.Shapes.Rectangle: rectangle :: (Real u, Floating u, FromPtSize u) => u -> u -> Shape u (Rectangle u)
- Wumpus.Drawing.Text.LRText: multiAlignCenter :: (Floating u, Real u, Ord u, FromPtSize u) => String -> BoundedLocGraphic u
+ Wumpus.Drawing.Text.LRText: multiAlignCenter :: (Real u, Floating u, FromPtSize u) => Radian -> String -> PosImage u (BoundingBox u)
- Wumpus.Drawing.Text.LRText: multiAlignLeft :: (Floating u, Real u, Ord u, FromPtSize u) => String -> BoundedLocGraphic u
+ Wumpus.Drawing.Text.LRText: multiAlignLeft :: (Real u, Floating u, FromPtSize u) => Radian -> String -> PosImage u (BoundingBox u)
- Wumpus.Drawing.Text.LRText: multiAlignRight :: (Floating u, Real u, Ord u, FromPtSize u) => String -> BoundedLocGraphic u
+ Wumpus.Drawing.Text.LRText: multiAlignRight :: (Real u, Floating u, FromPtSize u) => Radian -> String -> PosImage u (BoundingBox u)

Files

CHANGES view
@@ -1,4 +1,16 @@  0.1.0: -  * Initial split from Wumpus-Basic.+  * Initial release - this is a split from @Wumpus-Basic@ making +    the (very prototypical - read sub-alpha, unstable...) modules +    in the @Drawing@ hierarchy a separate package.++  * Simplified Chains - chains are now regular lists (though often+    infinite). Drawings are made with chains using new zip-like+    functions.++  * Re-worked Shapes.++  * Re-worked Arrow and Arrow Tip types.++  * Re-worked ConnectorPaths.
demo/ArrowCircuit.hs view
@@ -8,17 +8,18 @@  module ArrowCircuit where -import Wumpus.Basic.Kernel-import Wumpus.Basic.System.FontLoader.Afm-import Wumpus.Basic.System.FontLoader.GhostScript import Wumpus.Drawing.Arrows import Wumpus.Drawing.Paths  import Wumpus.Drawing.Shapes import Wumpus.Drawing.Text.LRText import Wumpus.Drawing.Text.SafeFonts -import Wumpus.Core                      -- package: wumpus-core+import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.System.FontLoader.Afm+import Wumpus.Basic.System.FontLoader.GhostScript +import Wumpus.Core                              -- package: wumpus-core+ import FontLoaderUtils  @@ -70,7 +71,7 @@           circuit_pic :: CtxPicture Double  circuit_pic = drawTracing $ do-    a1 <- drawi $ (strokedShape $ rrectangle 12 66 30) `at` P2 0 72+    a1 <- drawi $ rrectangle 12 66 30 `at` P2 0 72     atext a1 "CONST 0"     a2 <- drawi $ (strokedShape $ circle 16) `at` P2 120 60     atext a2 "IF"@@ -103,16 +104,19 @@          , TraceM m, DrawingCtxM m, u ~ MonUnit m )       => t -> String -> m () atext ancr ss = let pt = center ancr in-   drawi_ $ ctrCenterLine ss `at` pt+   drawi_ $ textAlignCenter ss `at` pt   ptext :: ( Real u, Floating u, FromPtSize u          , TraceM m, DrawingCtxM m, u ~ MonUnit m )       => Point2 u -> String -> m () ptext pt ss = localize (fontAttr times_italic 14) $ -    drawi_ $ ctrCenterLine ss `at` pt+    drawi_ $ textAlignCenter ss `at` pt  +-- Note - return type is a LocImage not a shape...+-- rrectangle :: (Real u, Floating u, FromPtSize u) -           => u -> u -> u -> LocShape u (Rectangle u)-rrectangle r w h = localize (roundCornerFactor $ realToFrac r) (rectangle w h)+           => u -> u -> u -> LocImage u (Rectangle u)+rrectangle r w h = +    localize (roundCornerFactor $ realToFrac r) $ strokedShape (rectangle w h)
demo/Arrowheads.hs view
@@ -3,12 +3,13 @@ module Arrowheads where  -import Wumpus.Basic.Kernel import Wumpus.Drawing.Arrows import Wumpus.Drawing.Chains import Wumpus.Drawing.Colour.SVGColours import Wumpus.Drawing.Paths hiding ( length ) +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+ import Wumpus.Core                              -- package: wumpus-core  import Data.AffineSpace                         -- package: vector-space@@ -60,10 +61,11 @@  tableGraphic :: (Real u, Floating u, FromPtSize u)               => [(Arrowhead u, Arrowhead u)] -> TraceDrawing u ()-tableGraphic tips = zipchainWith makeArrowDrawing tips ps+tableGraphic tips = +    draw $ unchainZipWith emptyLocGraphic makeArrowDrawing tips chn `at` start   where-    ps = tableDown 20 (120,24) (P2 0 480)-+    chn   = tableDown 20 (120,24)+    start = P2 0 480    std_ctx :: DrawingContext
demo/ClipPic.hs view
@@ -12,12 +12,14 @@  module ClipPic where -import Wumpus.Basic.Kernel import Wumpus.Drawing.Chains import Wumpus.Drawing.Colour.SVGColours import Wumpus.Drawing.Paths+import Wumpus.Drawing.Paths.MonadicConstruction import Wumpus.Drawing.Text.SafeFonts +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+ import Wumpus.Core                              -- package: wumpus-core  import Data.AffineSpace                         -- package: vector-space@@ -38,25 +40,24 @@   big_pic :: DCtxPicture-big_pic = pic1 `nextToV` zconcat [cpic1, cpic2, cpic3, cpic4]+big_pic = pic1 `cxpDown` oconcat cpic1 [cpic2, cpic3, cpic4]  fillPath :: Num u => Path u -> Graphic u fillPath = filledPath . toPrimPath  pic1 :: DCtxPicture-pic1 = drawTracing $-         localize (fillColour medium_slate_blue) $ do-            draw $ fillPath path01-            localize (fillColour powder_blue) $ -                     draw $ fillPath path02-            draw $ fillPath path03-            draw $ fillPath path04+pic1 = drawTracing $ localize (fillColour medium_slate_blue) $ do+    draw $ fillPath path01+    draw $ localize (fillColour powder_blue) $ fillPath path02+    draw $ fillPath path03+    draw $ fillPath path04   background :: RGBi -> DCtxPicture background rgb = drawTracing $ -    localize (strokeColour rgb) $ -        unchain 112 iheartHaskell $ tableDown 18 (86,16) (P2 0 288)+    draw $ localize (strokeColour rgb) $ ihh `at` P2 0 288+  where+    ihh = unchain 112 emptyLocGraphic iheartHaskell $ tableDown 18 (86,16)  cpic1 :: DCtxPicture  cpic1 = clipCtxPicture (toPrimPath path01) (background black)
demo/ColourCharts.hs view
@@ -4,9 +4,10 @@  import ColourChartUtils -import Wumpus.Basic.Kernel import Wumpus.Drawing.Chains +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+ import Wumpus.Core                              -- package: wumpus-core  import System.Directory@@ -42,11 +43,12 @@  tableGraphic :: Int -> [(String,RGBi)] -> TraceDrawing Double () tableGraphic row_count xs = -    zipchainWith (\(name,rgb) -> colourSample name rgb) xs ps+    draw $ unchainZip emptyLocGraphic gs chn `at` pt   where-    ps = tableDown row_count (152,11) pt-    pt = displaceV (fromIntegral $ 11 * row_count) zeroPt -+    chn  = tableDown row_count (152,11)+    pt   = displaceV (fromIntegral $ 11 * row_count) zeroPt +    gs   = map (uncurry colourSample) xs+     colourSample :: String -> RGBi -> LocGraphic Double colourSample name rgb = localize (fillColour rgb) $ 
demo/Connectors.hs view
@@ -3,12 +3,13 @@ module Connectors where  -import Wumpus.Basic.Kernel import Wumpus.Drawing.Arrows import Wumpus.Drawing.Chains import Wumpus.Drawing.Colour.SVGColours import Wumpus.Drawing.Paths hiding ( length ) +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+ import Wumpus.Core                              -- package: wumpus-core  import System.Directory@@ -50,10 +51,11 @@  tableGraphic :: (Real u, Floating u, FromPtSize u)               => [ConnectorPath u] -> TraceDrawing u ()-tableGraphic conns = zipchainWith makeConnDrawing conns ps+tableGraphic conns = +    draw $ unchainZipWith emptyLocGraphic makeConnDrawing conns chn `at` start   where-    ps = tableDown 10 (120,52) (displaceV 520 zeroPt)-+    chn   = tableDown 10 (120,52) +    start = P2 0 520     std_ctx :: DrawingContext
demo/DotPic.hs view
@@ -3,9 +3,7 @@ module DotPic where  -import Wumpus.Basic.Kernel-import Wumpus.Basic.System.FontLoader.Afm-import Wumpus.Basic.System.FontLoader.GhostScript+ import Wumpus.Drawing.Chains import Wumpus.Drawing.Colour.SVGColours import Wumpus.Drawing.Dots.AnchorDots@@ -13,6 +11,10 @@  import FontLoaderUtils +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.System.FontLoader.Afm+import Wumpus.Basic.System.FontLoader.GhostScript+ import Wumpus.Core                              -- package: wumpus-core  import Data.AffineSpace                         -- package: vector-space@@ -82,10 +84,11 @@  tableGraphic :: (Real u, Floating u, FromPtSize u)               => [DotLocImage u] -> TraceDrawing u ()-tableGraphic imgs = zipchainWith makeDotDrawing imgs ps+tableGraphic imgs = +    draw $ unchainZipWith emptyLocGraphic makeDotDrawing imgs chn `at` pt   where     row_count   = length imgs-    ps          = tableDown row_count (1,36) pt+    chn         = tableDown row_count (1,36)     pt          = displaceV (fromIntegral $ 36 * row_count) zeroPt   
demo/FeatureModel.hs view
@@ -5,17 +5,18 @@  module FeatureModel where -import Wumpus.Basic.Kernel-import Wumpus.Basic.System.FontLoader.Afm-import Wumpus.Basic.System.FontLoader.GhostScript import Wumpus.Drawing.Arrows import Wumpus.Drawing.Paths  import Wumpus.Drawing.Shapes import Wumpus.Drawing.Text.LRText import Wumpus.Drawing.Text.SafeFonts -import Wumpus.Core                      -- package: wumpus-core+import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.System.FontLoader.Afm+import Wumpus.Basic.System.FontLoader.GhostScript +import Wumpus.Core                              -- package: wumpus-core+ import FontLoaderUtils  @@ -26,7 +27,6 @@ main = do      (mb_gs, mb_afm) <- processCmdLine default_font_loader_help     createDirectoryIfMissing True "./out/"-    putStrLn "Note - text centering does not seem to be working well at present..."     maybe gs_failk  makeGSPicture  $ mb_gs     maybe afm_failk makeAfmPicture $ mb_afm   where@@ -95,7 +95,7 @@         => u -> String -> Point2 u -> TraceDrawing u (Box u) makeBox w ss pt = do      a <- drawi $ (strokedShape $ rectangle w 20) `at` pt-    drawi_ $ ctrCenterLine ss `at` center a+    drawi_ $ textAlignCenter ss `at` center a     -- draw  $ filledDisk 2 `at` center a     return a @@ -113,7 +113,7 @@ connWith arrh b0 b1 = do    lw <- getLineWidth    let p0 = south b0-   let p1 = northwards (realToFrac lw) b1+   let p1 = projectAnchor north (realToFrac lw) b1    drawi $ apply2R2 (rightArrow arrh connLine) p0 p1  infixr 4 `cmandatory`, `coptional`, `cmandatory_`, `coptional_`
demo/FontPic.hs view
@@ -2,12 +2,13 @@  module FontPic where -import Wumpus.Basic.Kernel import Wumpus.Drawing.Chains import Wumpus.Drawing.Colour.SVGColours ( steel_blue ) import Wumpus.Drawing.Colour.X11Colours ( indian_red1 ) import Wumpus.Drawing.Text.SafeFonts +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+ import Wumpus.Core                              -- package: wumpus-core  @@ -56,23 +57,26 @@   pointChain :: LocChain Double-pointChain = verticals $ map (fromIntegral . (+2)) point_sizes+pointChain = verticalSteps $ map (fromIntegral . (+2)) point_sizes -fontGraphic :: RGBi -> FontFace -> DPoint2 -> TraceDrawing Double ()-fontGraphic rgb ff pt = -    let ps = pointChain pt in -      zipchainWith (\sz -> makeLabel rgb ff sz) point_sizes ps +fontGraphic :: RGBi -> FontFace -> DLocGraphic +fontGraphic rgb ff = +    unchainZipWith emptyLocGraphic mkGF point_sizes pointChain +  where+    mkGF sz = makeLabel rgb ff sz + std_ctx :: DrawingContext std_ctx = standardContext 10   fontDrawing :: [(RGBi,FontFace)] -> DCtxPicture fontDrawing xs = drawTracing $  -    zipchainWithTD (\(rgb,ff) -> fontGraphic rgb ff) xs ps+    draw $ unchainZipWith emptyLocGraphic (uncurry fontGraphic) xs chn `at` start   where-    ps = tableDown 4 (1,180) (P2 0 (4*180))+    chn   = tableDown 4 (1,180)+    start = P2 0 (4*180)   
demo/LeftRightText.hs view
@@ -15,19 +15,19 @@  module LeftRightText where +import FontLoaderUtils -import Wumpus.Basic.Kernel-import Wumpus.Basic.System.FontLoader.Afm-import Wumpus.Basic.System.FontLoader.GhostScript import Wumpus.Drawing.Colour.SVGColours import Wumpus.Drawing.Dots.Marks import Wumpus.Drawing.Text.LRText import Wumpus.Drawing.Text.SafeFonts -import FontLoaderUtils +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.System.FontLoader.Afm+import Wumpus.Basic.System.FontLoader.GhostScript -import Wumpus.Core                      -- package: wumpus-core+import Wumpus.Core                              -- package: wumpus-core  import System.Directory @@ -66,43 +66,44 @@   makeCtx :: GlyphMetrics -> DrawingContext-makeCtx = fontFace helvetica . metricsContext 18+makeCtx = fontFace helvetica . metricsContext 14   text_pic :: CtxPicture Double text_pic = drawTracing $ do      drawi_ $ (fn left_text)       `at` P2   0 400-    drawi_ $ (fn center_text)     `at` P2 200 400-    drawi_ $ (fn right_text)      `at` P2 400 400+    drawi_ $ (fn center_text)     `at` P2 150 400+    drawi_ $ (fn right_text)      `at` P2 300 400     drawi_ $ (fn blank_text)      `at` P2   0 300-    drawi_ $ (fn bl_oneline)      `at` P2 200 300-    drawi_ $ (fn cc_oneline)      `at` P2 400 300-    drawi_ $ (fn newblr)          `at` P2   0 200-    drawi_ $ (fn newblc)          `at` P2 200 200-    drawi_ $ (fn newbll)          `at` P2 400 200-    drawi_ $ (fn rnewblr)         `at` P2   0 100-    drawi_ $ (fn rnewblc)         `at` P2 200 100-    drawi_ $ (fn rnewbll)         `at` P2 400 100+    drawi_ $ (fn ne_oneline)      `at` P2 150 300 +    drawi_ $ (fn cc_oneline)      `at` P2 300 300+++    drawi_ $ (fn sw_oneline)      `at` P2   0 200+    drawi_ $ (fn ss_oneline)      `at` P2 150 200+    drawi_ $ (fn se_oneline)      `at` P2 300 200+    drawi_ $ (fn swr_multi)       `at` P2   0 100+    drawi_ $ (fn ssr_multi)       `at` P2 150 100+    drawi_ $ (fn ner_multi)       `at` P2 300 100     drawi_ $ (fn rleft_text)      `at` P2   0 (-75)-    drawi_ $ (fn rcenter_text)    `at` P2 200 (-75)-    drawi_ $ (fn rright_text)     `at` P2 400 (-75)-      - +    drawi_ $ (fn rcenter_text)    `at` P2 150 (-75)+    drawi_ $ (fn rright_text)     `at` P2 300 (-75)+     draw $ redPlus            `at` P2   0 400-    draw $ redPlus            `at` P2 200 400-    draw $ redPlus            `at` P2 400 400+    draw $ redPlus            `at` P2 150 400+    draw $ redPlus            `at` P2 300 400     draw $ redPlus            `at` P2   0 300  -    draw $ redPlus            `at` P2 200 300 -    draw $ redPlus            `at` P2 400 300 +    draw $ redPlus            `at` P2 150 300 +    draw $ redPlus            `at` P2 300 300      draw $ redPlus            `at` P2   0 200  -    draw $ redPlus            `at` P2 200 200 -    draw $ redPlus            `at` P2 400 200  +    draw $ redPlus            `at` P2 150 200 +    draw $ redPlus            `at` P2 300 200       draw $ redPlus            `at` P2   0 100  -    draw $ redPlus            `at` P2 200 100 -    draw $ redPlus            `at` P2 400 100 +    draw $ redPlus            `at` P2 150 100 +    draw $ redPlus            `at` P2 300 100      draw $ redPlus            `at` P2   0 (-75)-    draw $ redPlus            `at` P2 200 (-75)-    draw $ redPlus            `at` P2 400 (-75)+    draw $ redPlus            `at` P2 150 (-75)+    draw $ redPlus            `at` P2 300 (-75)          where     fn = illustrateBoundedLocGraphic@@ -111,81 +112,73 @@ redPlus = localize (strokeColour red) markPlus  -newblc :: BoundedLocGraphic Double-newblc = -    localize (strokeColour dark_slate_gray) $ -        baseCenterLine "new baseline center" -newbll :: BoundedLocGraphic Double-newbll = -    localize (strokeColour dark_slate_gray) $ -        baseLeftLine "new baseline left"+-- single line+--+ne_oneline :: BoundedLocGraphic Double+ne_oneline = singleLine "north east" `startPos` NE -newblr :: BoundedLocGraphic Double-newblr = -    localize (strokeColour dark_slate_gray) $ -        baseRightLine "new baseline right" +-- single line+--+se_oneline :: BoundedLocGraphic Double+se_oneline = singleLine "south east" `startPos` SE -rnewblc :: BoundedLocGraphic Double-rnewblc = -    localize (strokeColour dark_slate_gray) $ -        rbaseCenterLine "baseline center" `rot` (0.25*pi)+-- single line+--+ss_oneline :: BoundedLocGraphic Double+ss_oneline = singleLine "south" `startPos` SS -rnewbll :: BoundedLocGraphic Double-rnewbll = -    localize (strokeColour dark_slate_gray) $ -        rbaseLeftLine "baseline left" `rot` (0.25*pi)+-- single line+--+sw_oneline :: BoundedLocGraphic Double+sw_oneline = singleLine "south west" `startPos` SW -rnewblr :: BoundedLocGraphic Double-rnewblr = -    localize (strokeColour dark_slate_gray) $ -        rbaseRightLine "baseline right" `rot` (0.25 * pi) +-- multi line+--+ssr_multi :: BoundedLocGraphic Double+ssr_multi = multiAlignCenter (0.25*pi) "south rot45" `startPos` SS -bl_oneline :: BoundedLocGraphic Double-bl_oneline = -    localize (strokeColour dark_slate_gray) $ baseLeftLine "Baseline-left..."+-- multi line+--+swr_multi :: BoundedLocGraphic Double+swr_multi = multiAlignCenter (0.25*pi) "south west rot45" `startPos` SW +-- multi line+--+ner_multi :: BoundedLocGraphic Double+ner_multi = multiAlignCenter (0.25*pi) "north east rot45" `startPos` NE + cc_oneline :: BoundedLocGraphic Double-cc_oneline = -    localize (strokeColour dark_slate_gray) $ ctrCenterLine "Center-center..."+cc_oneline = rsingleLine 0 "Center-center..."  `startPos` CENTER + blank_text :: BoundedLocGraphic Double-blank_text = -    localize (strokeColour dark_slate_gray) $ multiAlignCenter ""+blank_text = multiAlignCenter 0 "" `startPos` CENTER   left_text :: BoundedLocGraphic Double-left_text = -    localize (strokeColour dark_slate_gray) $ multiAlignLeft dummy_text+left_text = multiAlignLeft 0 dummy_text `startPos` CENTER   right_text :: BoundedLocGraphic Double-right_text = -    localize (strokeColour dark_slate_gray) $ multiAlignRight dummy_text+right_text = multiAlignRight 0 dummy_text `startPos` CENTER  center_text :: BoundedLocGraphic Double-center_text = -    localize (strokeColour dark_slate_gray) $ multiAlignCenter dummy_text+center_text = multiAlignCenter 0 dummy_text `startPos` CENTER   rleft_text :: BoundedLocGraphic Double-rleft_text = -    localize (strokeColour dark_slate_gray) $ -        rmultiAlignLeft dummy_text `rot`   (0.25*pi)+rleft_text = multiAlignLeft (0.25*pi)  dummy_text `startPos` CENTER   rright_text :: BoundedLocGraphic Double-rright_text = -    localize (strokeColour dark_slate_gray) $ -        rmultiAlignRight dummy_text `rot`  (0.25*pi)+rright_text = multiAlignRight (0.25*pi) dummy_text `startPos` CENTER  rcenter_text :: BoundedLocGraphic Double-rcenter_text = -    localize (strokeColour dark_slate_gray) $ -        rmultiAlignCenter dummy_text `rot` (0.25*pi)+rcenter_text = multiAlignCenter (0.25*pi) dummy_text `startPos` CENTER   dummy_text :: String 
demo/PetriNet.hs view
@@ -7,9 +7,6 @@  module PetriNet where -import Wumpus.Basic.Kernel-import Wumpus.Basic.System.FontLoader.Afm-import Wumpus.Basic.System.FontLoader.GhostScript import Wumpus.Drawing.Arrows import Wumpus.Drawing.Colour.SVGColours import Wumpus.Drawing.Paths@@ -19,6 +16,10 @@  import FontLoaderUtils +import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.System.FontLoader.Afm+import Wumpus.Basic.System.FontLoader.GhostScript+ import Wumpus.Core                              -- package: wumpus-core  @@ -96,19 +97,20 @@     draw $ lblParensParens `at` (P2 (-36) 150)     draw $ lblParensParens `at` (P2 300 60)     draw $ lblParensParensParens `at` (P2 (-52) (-14))-    draw $ lblBold "processing_w"   `at` (southwards 12 pw)-    draw $ lblBold "ready_to_write" `at` (southwards 12 rtw)-    draw $ lblBold "writing"        `at` (southwards 12 w)+    draw $ lblBold "processing_w"   `at` (projectAnchor south 12 pw)+    draw $ lblBold "ready_to_write" `at` (projectAnchor south 12 rtw)+    draw $ lblBold "writing"        `at` (projectAnchor south 12 w)     draw $ lblBold' "resource"      `at` (P2 300 72)-    draw $ lblBold "processing_r"   `at` (northwards 12 pr)-    draw $ lblBold "ready_to_read"  `at` (northwards 12 rtr)-    draw $ lblBold "reading"        `at` (northwards 12 r)+    draw $ lblBold "processing_r"   `at` (projectAnchor north 12 pr)+    draw $ lblBold "ready_to_read"  `at` (projectAnchor north 12 rtr)+    draw $ lblBold "reading"        `at` (projectAnchor north 12 r)     return ()  greenFill :: DrawingCtxM m => m a -> m a greenFill = localize (fillColour lime_green) -place :: (Real u, Floating u, DrawingCtxM m, TraceM m, u ~ MonUnit m) +place :: ( Real u, Floating u, FromPtSize u+         , DrawingCtxM m, TraceM m, u ~ MonUnit m )        => u -> u -> m (Circle u) place x y = greenFill $ drawi $ (borderedShape $ circle 14) `at` P2 x y @@ -153,6 +155,6 @@   lblBold :: (Real u, Floating u, FromPtSize u) => String -> LocGraphic u-lblBold ss = localize (fontFace helvetica_bold) $ post $ ctrCenterLine ss-  where-    post = fmap (replaceL uNil)+lblBold ss = localize (fontFace helvetica_bold) $ +                ignoreAns $ textAlignCenter ss+
− demo/PictureCompo.hs
@@ -1,151 +0,0 @@-{-# OPTIONS -Wall #-}--module PictureCompo where--import Wumpus.Basic.Kernel-import Wumpus.Drawing.Colour.SVGColours--import Wumpus.Core                              -- package: wumpus-core--import System.Directory---main :: IO ()-main = do -    createDirectoryIfMissing True "./out/"-    let out1 = runCtxPictureU pic_drawing_ctx pictures-    writeEPS "./out/picture_composition.eps" out1-    writeSVG "./out/picture_composition.svg" out1---pic_drawing_ctx :: DrawingContext-pic_drawing_ctx = standardContext 14---pictures :: DCtxPicture-pictures = vsep 12 [ pic1,  pic2,  pic3,  pic4-                   , pic5,  pic6,  pic7,  pic8-                   , pic9,  pic10, pic11, pic12 ]---drawBlueBounds :: (Real u, Floating u, FromPtSize u) -               => CtxPicture u -> CtxPicture u-drawBlueBounds = mapCtxPicture (illustrateBounds blue)--pic1 :: DCtxPicture-pic1 = picAnno pic "red `over` green `over` blue"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ rect_red `over` rect_green `over` rect_blue--pic2 :: DCtxPicture-pic2 = picAnno pic "red `under` green `under` blue"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ rect_red `under` rect_green `under` rect_blue---pic3 :: DCtxPicture -pic3 = picAnno pic "red `centric` green `centric` blue"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            rect_red `centric` rect_green `centric` rect_blue---- Note - nextToH only moves pictures in the horizontal.----pic4 :: DCtxPicture -pic4 = picAnno pic "red `nextToH` green `nextToH` blue"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            rect_red `nextToH` rect_green `nextToH` rect_blue---- Note - nextToV only moves pictures in the vertical.----pic5 :: DCtxPicture -pic5 = picAnno pic "red `nextToV` green `nextToV` blue"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            rect_red `nextToV` rect_green `nextToV` rect_blue---pic6 :: DCtxPicture-pic6 = picAnno pic "zconcat [red, green, blue]"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            zconcat [rect_red, rect_green, rect_blue]---pic7 :: DCtxPicture-pic7 = picAnno pic "hcat [red, green, blue]"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            hcat [rect_red, rect_green, rect_blue]--pic8 :: DCtxPicture-pic8 = picAnno pic "vcat [red, green, blue]"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            vcat [rect_red, rect_green, rect_blue]--pic9 :: DCtxPicture-pic9 = picAnno pic "hsep 20 [red, green, blue]"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            hsep 20 [rect_red, rect_green, rect_blue]--pic10 :: DCtxPicture-pic10 = picAnno pic "vsep 20 [red, green, blue]"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            vsep 20 [rect_red, rect_green, rect_blue]---pic11 :: DCtxPicture-pic11 = picAnno pic "hcatA HTop [red, green, blue]"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            hcatA HTop [rect_red, rect_green, rect_blue]---pic12 :: DCtxPicture-pic12 = picAnno pic "vcatA VCenter [red, green, blue]"-  where-    pic :: DCtxPicture-    pic = drawBlueBounds $ -            vcatA VCenter [rect_red, rect_green, rect_blue]--------------------------------------------------------------------------------------picAnno :: DCtxPicture -> String -> DCtxPicture-picAnno pic msg = alignHSep HCenter 30 pic lbl-  where-    lbl = drawTracing $ draw $ textline msg `at` zeroPt---rect_red :: DCtxPicture-rect_red = drawTracing $ -    localize (fillColour indian_red)-             (draw $ borderedRectangle 30 10 `at` (P2 0 10))-                 -rect_green :: DCtxPicture-rect_green = drawTracing $ -    localize (fillColour olive_drab)-             (draw $ borderedRectangle 15 15 `at` (P2 10 10))---rect_blue :: DCtxPicture-rect_blue = drawTracing $ -    localize (fillColour powder_blue)-             (draw $ borderedRectangle 20 30 `at` (P2 10 0))-
+ demo/SampleShapes.hs view
@@ -0,0 +1,206 @@+{-# LANGUAGE TypeFamilies               #-}+{-# OPTIONS -Wall #-}+++module SampleShapes where+++import FontLoaderUtils++import Wumpus.Drawing.Colour.SVGColours+import Wumpus.Drawing.Dots.Marks+import Wumpus.Drawing.Shapes+import Wumpus.Drawing.Text.LRText+import Wumpus.Drawing.Text.SafeFonts++import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.System.FontLoader.Afm+import Wumpus.Basic.System.FontLoader.GhostScript+++import Wumpus.Core                              -- package: wumpus-core++import Control.Monad+import System.Directory+++main :: IO ()+main = do +    (mb_gs, mb_afm) <- processCmdLine default_font_loader_help+    createDirectoryIfMissing True "./out/shapes/"+    maybe gs_failk  (makeGSPicture shape_list)  $ mb_gs+    maybe afm_failk (makeAfmPicture shape_list) $ mb_afm+  where+    gs_failk  = putStrLn "No GhostScript font path supplied..."+    afm_failk = putStrLn "No AFM v4.1 font path supplied..."+++makeGSPicture :: ShapeList -> FilePath -> IO ()+makeGSPicture shapes font_dir = do+    putStrLn "Using GhostScript metrics..."+    (gs_metrics, msgs) <- loadGSMetrics font_dir ["Courier"]+    mapM_ putStrLn msgs+    mapM_ (out1 gs_metrics) shapes +  where+    out1 gs_metrics (name, shape_pic) = do +       let pic1 = runCtxPictureU (makeCtx gs_metrics) $ shape_pic name+       writeEPS ("./out/shapes/" ++ name ++ "01.eps") pic1+       writeSVG ("./out/shapes/" ++ name ++ "01.svg") pic1+++makeAfmPicture :: ShapeList -> FilePath -> IO ()+makeAfmPicture shapes font_dir = do+    putStrLn "Using AFM 4.1 metrics..."+    (afm_metrics, msgs) <- loadAfmMetrics font_dir ["Courier"]+    mapM_ putStrLn msgs+    mapM_ (out1 afm_metrics) shapes +  where+    out1 afm_metrics (name, shape_pic) = do +        let pic1 = runCtxPictureU (makeCtx afm_metrics) $ shape_pic name+        writeEPS ("./out/shapes/" ++ name ++ "02.eps") pic1+        writeSVG ("./out/shapes/" ++ name ++ "02.svg") pic1++type ShapeList = [(String, (String -> DCtxPicture))]+++shape_list :: ShapeList+shape_list = +    [ ( "circle"+      , shapePic voidExtra $ circle 150)+    , ( "diamond"+      ,  shapePic (apexAnchor >=> midPoints 4) $ diamond 150 100)+    , ( "ellipse"+      , shapePic voidExtra $ ellipse 150 100)+    , ( "invsemicircle"+      , shapePic (apexAnchor >=> topCorners) $ invsemicircle 150)+    , ( "invsemiellipse"+      , shapePic (apexAnchor >=> topCorners) $ invsemiellipse 100 150)+    , ( "invtriangle"+      , shapePic (apexAnchor >=> topCorners >=> midPoints 3) $ +          invtriangle 300 150)+    , ( "parallelogram"+      , shapePic (topCorners >=> bottomCorners >=> midPoints 4) $ +          zparallelogram 250 200)+    , ( "rectangle"+      , shapePic (topCorners >=> bottomCorners >=> midPoints 4) $ +          rectangle 300 175)+    , ( "semicircle"+      , shapePic (apexAnchor >=> bottomCorners) $ semicircle 150) +    , ( "semiellipse"+      , shapePic (apexAnchor >=> bottomCorners) $ semiellipse 100 150) +    , ( "trapezium"+      ,  shapePic (bottomCorners >=> topCorners >=> midPoints 4) $ +          ztrapezium 300 150)+    , ( "triangle"+      , shapePic (apexAnchor >=> bottomCorners >=> midPoints 3) $ +          triangle 300 150 )+    ]++makeCtx :: GlyphMetrics -> DrawingContext+makeCtx = fontFace courier . metricsContext 16++rotate05 :: Rotate a => a -> a+rotate05 = rotate (d2r (5::Double))++-- Extra elaboration...++voidExtra :: a -> TraceDrawing u ()+voidExtra _ = return ()++apexAnchor :: ( Real u, Floating u, FromPtSize u+            , ApexAnchor a+            , u ~ DUnit a )+            => a -> TraceDrawing u a+apexAnchor a = do+    draw $ label EAST   "(apex)"    `at` apex  a+    return a++bottomCorners :: ( Real u, Floating u, FromPtSize u+               , BottomCornerAnchor a+               , u ~ DUnit a )+            => a -> TraceDrawing u a+bottomCorners a = do+    draw $ label SOUTH_WEST   "(bottom left)"    `at` bottomLeftCorner  a+    draw $ label SOUTH_EAST   "(bottom right)"   `at` bottomRightCorner a+    return a++topCorners :: ( Real u, Floating u, FromPtSize u+              , TopCornerAnchor a+              , u ~ DUnit a )+           => a -> TraceDrawing u a+topCorners a = do+    draw $ label NORTH_WEST   "(top left)"    `at` topLeftCorner  a+    draw $ label NORTH_EAST   "(top right)"   `at` topRightCorner a+    return a+++midPoints :: ( Real u, Floating u, FromPtSize u+             , SideMidpointAnchor a+             , u ~ DUnit a )+          => Int -> a -> TraceDrawing u a+midPoints n a = mapM_ mf [1..n] >> return a+  where+    mf i = let msg = "(side midpt " ++ show i ++ ")"+           in draw $ label EAST  msg    `at` sideMidpoint i  a+++++shapePic :: ( CenterAnchor a, CardinalAnchor a, CardinalAnchor2 a+            , RadialAnchor a+            , Scale a, Rotate a+            , DUnit a ~ Double) +         => (a -> DTraceDrawing b) -> DShape a -> String -> DCtxPicture+shapePic mf sh name = drawTracing $ do+    a1  <- localize shapeSty $ drawi $ +              uniformScale 2 $ rotate05 $ shape `at` (P2 100 0)+    draw $ label NORTH        "(center)"      `at` center a1+    draw $ label NORTH        "(north)"       `at` north a1+    draw $ label SOUTH        "(south)"       `at` south a1+    draw $ label EAST         "(east)"        `at` east a1+    draw $ label WEST         "(west)"        `at` west a1+    draw $ label NORTH_EAST   "(northeast)"   `at` northeast a1+    draw $ label NORTH_WEST   "(northwest)"   `at` northwest a1+    draw $ label SOUTH_EAST   "(southeast)"   `at` southeast a1+    draw $ label SOUTH_WEST   "(southwest)"   `at` southwest a1+    draw $ label EAST         "(10 deg)"      `at` radialAnchor deg10 a1+    draw $ label NORTH_WEST   "(110 deg)"     `at` radialAnchor deg110 a1+    draw $ label WEST         "(190 deg)"     `at` radialAnchor deg190 a1+    draw $ label NORTH        "(250 deg)"     `at` radialAnchor deg250 a1+    _ <- mf a1+    return ()    +  where+    shape   = strokedShape $ setDecoration textF sh+    textF   = lift1R2 $ ignoreAns (multiAlignCenter 0 name `startPos` CENTER)++    deg10   = d2r (10::Double)+    deg110  = d2r (110::Double)+    deg190  = d2r (190::Double)+    deg250  = d2r (250::Double)+++++++shapeSty :: DrawingContextF+shapeSty = strokeColour light_steel_blue . ultrathick++label :: (Real u, Floating u, FromPtSize u) +           => Cardinal -> String -> LocGraphic u+label cpos ss = markX `oplus` msg+  where+    (rpos,fn)     = go cpos+    msg           = ignoreAns $ moveStart (fn 10) $ +                       multiAlignCenter 0 ss `startPos` rpos++    go NORTH      = (SS, northwards)+    go NORTH_EAST = (SW, northeastwards)+    go EAST       = (WW, eastwards) +    go SOUTH_EAST = (NW, southeastwards)+    go SOUTH      = (NN, southwards)+    go SOUTH_WEST = (NE, southwestwards)+    go WEST       = (EE, westwards)+    go NORTH_WEST = (SE, northwestwards)+  +
+ demo/SingleLine.hs view
@@ -0,0 +1,80 @@+{-# OPTIONS -Wall #-}+++module SingleLine where++import FontLoaderUtils++import Wumpus.Drawing.Colour.SVGColours+import Wumpus.Drawing.Text.LRText+import Wumpus.Drawing.Text.SafeFonts++import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.System.FontLoader.Afm+import Wumpus.Basic.System.FontLoader.GhostScript++import Wumpus.Core                              -- package: wumpus-core++import System.Directory+++main :: IO ()+main = do +    (mb_gs, mb_afm) <- processCmdLine default_font_loader_help+    createDirectoryIfMissing True "./out/"+    maybe gs_failk  makeGSPicture  $ mb_gs+    maybe afm_failk makeAfmPicture $ mb_afm+  where+    gs_failk  = putStrLn "No GhostScript font path supplied..."+    afm_failk = putStrLn "No AFM v4.1 font path supplied..."+++makeGSPicture :: FilePath -> IO ()+makeGSPicture font_dir = do+    putStrLn "Using GhostScript metrics..."+    (gs_metrics, msgs) <- loadGSMetrics font_dir ["Helvetica"]+    mapM_ putStrLn msgs+    let pic1 = runCtxPictureU (makeCtx gs_metrics) drawing01+    writeEPS "./out/single_line01.eps" pic1+    writeSVG "./out/single_line01.svg" pic1++makeAfmPicture :: FilePath -> IO ()+makeAfmPicture font_dir = do+    putStrLn "Using AFM 4.1 metrics..."+    (afm_metrics, msgs) <- loadAfmMetrics font_dir ["Helvetica"]+    mapM_ putStrLn msgs+    let pic2 = runCtxPictureU (makeCtx afm_metrics) drawing01+    writeEPS "./out/single_line02.eps" pic2+    writeSVG "./out/single_line02.svg" pic2++++makeCtx :: GlyphMetrics -> DrawingContext+makeCtx = fontFace helvetica . metricsContext 12++++drawing01 :: DCtxPicture+drawing01 = drawTracing $ localize (fillColour red) $ mf +++mf :: (Real u, Floating u, FromPtSize u) => TraceDrawing u ()+mf = do+    draw $ testDraw NN `at` (P2   0 200)+    draw $ testDraw SS `at` (P2  75 200)+    draw $ testDraw EE `at` (P2 150 200)+    draw $ testDraw WW `at` (P2 225 200)+    draw $ testDraw NE `at` (P2   0 100)+    draw $ testDraw SE `at` (P2  75 100)+    draw $ testDraw SW `at` (P2 150 100)+    draw $ testDraw NW `at` (P2 225 100)+    draw $ testDraw CENTER    `at` (P2   0 0)+    ++testDraw :: (Real u, Floating u, FromPtSize u) => RectPosition -> LocGraphic u+testDraw rpos = filledDisk 2 `oplus` (ignoreAns ans)+  where+    ans = singleLine "Qwerty" `startPos` rpos+++
demo/Symbols.hs view
@@ -2,11 +2,10 @@  module Symbols where -import Wumpus.Basic.Kernel import Wumpus.Drawing.Chains import Wumpus.Drawing.Text.SafeFonts -+import Wumpus.Basic.Kernel                      -- package: wumpus-basic import Wumpus.Core                              -- package: wumpus-core  import Prelude hiding ( pi, product )@@ -32,12 +31,14 @@ -- symbols :: DCtxPicture symbols = drawTracing $ do-    localize (fontFace symbol) $ zipchainWith sdraw all_letters ps-    zipchainWith ldraw all_letters ps+    draw $ localize (fontFace symbol) $ +            unchainZipWith emptyLocGraphic sdraw all_letters chn `at` start+    draw $ unchainZipWith emptyLocGraphic ldraw all_letters chn `at` start   where-    ps              = tableDown 30 (100,20) (P2 0 (30*20))+    chn             = tableDown 30 (100,20) +    start           = P2 0 (30*20)     sdraw (s,_)     = textline s-    ldraw (_,name)  = moveStartPoint (displaceH 16) (textline name)+    ldraw (_,name)  = moveStart (displaceH 16) (textline name)   all_letters :: [(String, String)]
demo/TableChains.hs view
@@ -3,15 +3,14 @@ module TableChains where  -import Wumpus.Basic.Kernel-import Wumpus.Drawing.Chains import Wumpus.Drawing.Colour.SVGColours+import Wumpus.Drawing.Grids +import Wumpus.Basic.Kernel                      -- package: wumpus-basic import Wumpus.Core                              -- package: wumpus-core  import System.Directory - main :: IO () main = do      createDirectoryIfMissing True "./out/"@@ -19,10 +18,16 @@     writeEPS "./out/table_chains01.eps" pic1     writeSVG "./out/table_chains01.svg" pic1 -table_drawing :: CtxPicture Double-table_drawing = drawTracing $ tableGraphic+std_ctx :: DrawingContext+std_ctx = fillColour peru $ standardContext 18 +table_drawing :: CtxPicture Double+table_drawing = drawTracing $ do +--    tableGraphic+    draw $ connect (interiorGrid 10) (P2 (-20) (-20)) (P2 150 80)+    draw $ grid (3,2) 20 `at` (P2 300 60) +{- tableGraphic :: (Real u, Floating u, FromPtSize u)               => TraceDrawing u () tableGraphic = do @@ -34,11 +39,12 @@     downs   = tableDown  4 (36,24) dstart     rights  = tableRight 5 (36,24) rstart -    dstart  = P2 0   480-    rstart  = P2 240 480-+    dstart  = P2 0   200   -- note grows down...+    rstart  = P2 240 200   -- ditto+-}  -std_ctx :: DrawingContext-std_ctx = fillColour peru $ standardContext 18+++  
src/Wumpus/Drawing/Chains/Base.hs view
@@ -3,7 +3,7 @@ -------------------------------------------------------------------------------- -- | -- Module      :  Wumpus.Drawing.Chains.Base--- Copyright   :  (c) Stephen Tetley 2010-2011+-- Copyright   :  (c) Stephen Tetley 2011 -- License     :  BSD3 -- -- Maintainer  :  stephen.tetley@gmail.com@@ -12,25 +12,24 @@ -- -- Generate points in an iterated chain. ----- \*\* WARNING \*\* - unstable. Names are not so good, also --- Wumpus-Basic has a @chain1@ operator...--- --------------------------------------------------------------------------------  module Wumpus.Drawing.Chains.Base   ( -    Chain+    PointChain   , LocChain-  , unchain-  , zipchain-  , zipchainWith--  , unchainTD-  , zipchainTD-  , zipchainWithTD+  , ConnectorChain +  -- * Unrolling chains+  , unchain+  , unchainU+  , unchainZip+  , unchainZipWith+  , unconnectorChain +  -- * Building chains+  , liftChainF    ) where @@ -40,78 +39,221 @@   --- | A 'Chain' is a list of points. The list is often expected to --- be inifinte, but if it was a Stream  it would loose the ability--- to use list comprehensions.+-- | A 'PointChain' is a list of points.  -- -type Chain u = [Point2 u]+-- The list is typically inifinte so some attention must be given +-- to choosing a chain drawing function and using it appropriately.+-- +type PointChain u = [Point2 u]  --- | A LocChain is a function from a starting point to a 'Chain'.+-- | A LocChain is a function from a starting point to a +-- 'PointChain'.+--+-- The list is often expected to be inifinte, but if it was a +-- Stream it would loose the ability to use list comprehensions. -- -type LocChain u = Point2 u -> Chain u+type LocChain u = LocDrawingInfo u (PointChain u)  --- | Note - commonly a 'Chain' may be infinite, so it is only --- unrolled a finite number of times.----unchain :: Int -> LocGraphic u -> Chain u -> TraceDrawing u ()-unchain i op chn = go i chn-  where-    go n _      | n <= 0 = return ()-    go _ []              = return () -    go n (x:xs)          = draw (op `at` x) >> go (n-1) xs+-- | A ConnectorChain is a function from a start- and end-point +-- to a 'Chain'.+-- +type ConnectorChain u = ConnectorCF u (PointChain u)    +-- | 'unchain' : @ unroll_count * alt_fun * draw_fun * chain -> LocCF @+-- +-- Unroll the chain, applying the @draw_fun@ to each point +-- producing a LocCF (usually a 'LocGraphic'). If the chain does +-- not produce any points the @alt_fun@ is applied to the start +-- point.+--+-- Note - commonly a 'Chain' may be infinite, so it is only +-- unrolled a finite number of times - the @unrool_count@.+--+-- This function has a very general type signature commonly it +-- will be used at these types:+--+-- > unchain :: (Num u, OPlus a) => +-- >     Int -> LocImage u a -> LocImage u a -> LocChain u -> LocImage u a+-- >+-- > unchain :: Num u => +-- >     Int -> LocGraphic u -> LocGraphic u -> LocChain u -> LocGraphic u+--+unchain :: (Num u, OPlus a) +        => Int +        -> LocCF u (ImageAns u a) +        -> LocCF u (ImageAns u a) +        -> LocChain u +        -> LocCF u (ImageAns u a)+unchain i alt _  _   | i <= 0 = alt+unchain i alt gf chn          = promoteR1 $ \p0 -> +    (chn `at` p0) >>= \pts -> case pts of +      []     -> alt `at` p0+      [x]    -> gf  `at` x+      (x:xs) -> go x (take (i-1) xs)+  where+    go x []     = gf `at` x+    go x (y:ys) = (gf `at` x) `oplus` go y ys  -zipchain :: [LocGraphic u] -> Chain u -> TraceDrawing u ()-zipchain (g:gs) (p:ps)   = draw (g `at` p) >> zipchain gs ps-zipchain _      _        = return ()  -zipchainWith :: (a -> LocGraphic u) -> [a] -> Chain u -> TraceDrawing u ()-zipchainWith op xs chn = go xs chn +-- | 'unchain' : @ alt_fun * draw_fun * chain -> LocCF @+-- +-- /Unsafe/ version of 'unchain' - this function assumes the chain+-- is finite which is not usually the case.+--+-- This function has a very general type signature commonly it +-- will be used at these type:+--+-- > unchainU :: (Num u, OPlus a) => +-- >     LocImage u a -> LocImage u a -> LocChain u -> LocImage u a+-- >+-- > unchainU :: Num u => +-- >     LocGraphic u -> LocGraphic u -> LocChain u -> LocGraphic u+--+-- \*\* WARNING \*\* - if the chain is infinite this function will +-- not terminate.+--+unchainU :: (Num u, OPlus a)+         => LocCF u (ImageAns u a) +         -> LocCF u (ImageAns u a) +         -> LocChain u +         -> LocCF u (ImageAns u a)+unchainU alt gf chn = promoteR1 $ \p0 -> +    (chn `at` p0) >>= \pts -> case pts of +      []     -> alt `at` p0+      [x]    -> gf  `at` x+      (x:xs) -> go x xs   where-    go (a:as) (p:ps)   = draw (op a `at` p) >> go as ps-    go _      _        = return ()-+    go x []     = gf `at` x+    go x (y:ys) = (gf `at` x) `oplus` go y ys  --- | Variant of 'unchain' where the drawing argument is a --- @TraceDrawing@ not a @LocGraphic@. +-- | 'unchainZip' : @ alt_fun * [draw_fun] * chain -> LocCF @+-- +-- Unroll the chain, zipping the list of @draw_funs@ to the list+-- of points producing a LocCF (usually a 'LocGraphic'). If the +-- chain does not produce any points the @alt_fun@ is applied to +-- the start point. ---unchainTD :: Int -> (Point2 u -> TraceDrawing u ()) -> Chain u -> TraceDrawing u ()-unchainTD i op chn = go i chn+-- This function has a very general type signature commonly it +-- will be used at these types:+--+-- > unchainZip :: (Num u, OPlus a) => +-- >     LocImage u a -> [LocImage u a] -> LocChain u -> LocImage u a+-- >+-- > unchainZip :: Num u => +-- >     LocGraphic u -> [LocGraphic u] -> LocChain u -> LocGraphic u+--+-- \*\* WARNING \*\* - the list of drawing functions should be +-- finite. If both the list of drawing functions and the chain are +-- infinite this function will not terminate.+-- +unchainZip :: (Num u, OPlus a) +           => LocCF u (ImageAns u a) +           -> [LocCF u (ImageAns u a)] +           -> LocChain u +           -> LocCF u (ImageAns u a)+unchainZip alt []     _   = promoteR1 $ \p0 -> alt `at` p0+unchainZip alt  (g:gs) chn = promoteR1 $ \p0 -> +    (chn `at` p0) >>= \pts -> case pts of +      []     -> alt `at` p0+      [x]    -> g `at` x+      (x:xs) -> go (g `at` x) gs xs   where-    go n _      | n <= 0 = return ()-    go _ []              = return () -    go n (x:xs)          = (op x) >> go (n-1) xs+    go acc _      []     = acc+    go acc []     _      = acc+    go acc (f:fs) (p:ps) = go (acc `oplus` (f `at` p)) fs ps  -zipchainTD :: [Point2 u -> TraceDrawing u ()] -> Chain u -> TraceDrawing u ()-zipchainTD (g:gs) (p:ps)   = g p >> zipchainTD gs ps-zipchainTD _      _        = return () +-- | 'unchainZipWith' : @ alt_fun * (a -> draw_fun) * [a] * chain -> LocCF @+-- +-- Version of 'unchainZip' where the list is some data rather +-- than a drawing function and the @(a -> draw_fun)@ builder is +-- applied to each element as part of the unrolling.+-- +-- Approximately this function is a @zipWith@ to the @zip@ of +-- @unchainZip@.+--+-- This function has a very general type signature commonly it +-- will be used at these type:+--+-- > unchainZipWith :: (Num u, OPlus a) => +-- >     LocImage u a -> (s -> LocImage u a) -> [s] -> LocChain u -> LocImage u a+-- >+-- > unchainZipWith :: Num u => +-- >     LocGraphic u -> (s -> LocGraphic u) -> [s] -> LocChain u -> LocGraphic u+--+-- \*\* WARNING \*\* - if the chain and list are infinite this +-- function will not terminate.+--+unchainZipWith :: (Num u, OPlus a)+                => LocCF u (ImageAns u a) +                -> (s -> LocCF u (ImageAns u a))+                -> [s]+                -> LocChain u +                -> LocCF u (ImageAns u a)+unchainZipWith alt _    []     _   = promoteR1 $ \p0 -> alt `at` p0+unchainZipWith alt mkGF (s:ss) chn = promoteR1 $ \p0 -> +    (chn `at` p0) >>= \pts -> case pts of +      []     -> alt `at` p0+      [x]    -> mkGF s `at` x+      (x:xs) -> go (mkGF s `at` x) ss xs+  where+    go acc _      []     = acc+    go acc []     _      = acc+    go acc (t:ts) (p:ps) = go (acc `oplus` (mkGF t `at` p)) ts ps  -zipchainWithTD :: (a -> Point2 u -> TraceDrawing u ()) -> [a] -> Chain u -> TraceDrawing u ()-zipchainWithTD op xs chn = go xs chn +++-- | 'unconnectorChain' : @ alt_fun * draw_fun * conn_chain -> ConnectorCF @+--+-- Unroll the chain produced between the implicit start and end +-- points. Apply the @draw_fun@ to each point producing a +-- ConnectorCF (usually a 'ConnectorGraphic'). If the chain does +-- not produce any points, the @alt_fun@ is applied to the start +-- and end points.+--+-- This function has a very general type signature commonly it +-- will be used at these types:+--+-- > unconnectorChain :: (Num u, OPlus a) => +-- >     ConnectorImage u a -> LocImage u a -> ConnectorChain u -> ConnectorImage u a+-- >+-- > unconnectorChain :: Num u => +-- >     ConnectorGraphic u -> LocGraphic u -> ConnectorChain u -> ConnectorGraphic u+--+--+unconnectorChain :: (Num u, OPlus a) +                 => ConnectorCF u (ImageAns u a) +                 -> LocCF u (ImageAns u a) +                 -> ConnectorChain u +                 -> ConnectorCF u (ImageAns u a)+unconnectorChain alt gf cchn = promoteR2 $ \p0 p1 -> +    (connect cchn p0 p1) >>= \pts -> case pts of+      []     -> connect alt p0 p1+      [x]    -> gf `at` x+      (x:xs) -> go (gf `at` x) xs   where-    go (a:as) (p:ps)   = op a p >> go as ps-    go _      _        = return ()+    go acc []     = acc+    go acc (p:ps) = go (acc `oplus` (gf `at` p)) ps   --- Notes - something like TikZ\'s chains could possibly be --- achieved with a Reader monad (@local@ initially seems better --- for \"state change\" than @set@ as local models a stack). ++--------------------------------------------------------------------------------++-- | 'liftChainF' : @ (point -> [point]) -> LocChain @ ----- It\'s almost tempting to put point-supply directly in the--- Trace monad so that TikZ style chaining is transparent.--- (The argument against is: how compatible this would be with--- the Turtle monad for example?).+-- Lift a pure chain generating function inot a 'LocChain'. --+liftChainF :: (Point2 u -> PointChain u) -> LocChain u+liftChainF fn = promoteR1 $ \pt -> return $ fn pt 
src/Wumpus/Drawing/Chains/Derived.hs view
@@ -22,18 +22,25 @@     tableDown   , tableRight -  , horizontal-  , vertical+  , horizontalPoints+  , verticalPoints -  , horizontals-  , verticals+  , horizontalSteps+  , verticalSteps +  , innerHorizontals+  , innerVerticals+   ) where  import Wumpus.Drawing.Chains.Base  import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Core                              -- package: wumpus-core ++import Data.List + -------------------------------------------------------------------------------- -- Tables @@ -47,11 +54,11 @@ -- @top-left@. -- tableDown :: Num u => Int -> (u,u) -> LocChain u-tableDown n (rw,rh) pt = map fn ints+tableDown n (rw,rh) = liftChainF $ \pt -> map (fn pt) ints   where-    ints = iterate (+1) 0-    fn i = let (x,y) = i `divMod` n -           in displace (rw * fromIntegral x) (rh * fromIntegral (-y)) pt+    ints    = iterate (+1) 0+    fn pt i = let (x,y) = i `divMod` n +              in displace (rw * fromIntegral x) (rh * fromIntegral (-y)) pt   -- | 'tableRight' : @ num_cols * row_width * row_height -> LocChain @@@ -62,56 +69,45 @@ -- This chain is infinite. -- tableRight :: Num u => Int -> (u,u) -> LocChain u-tableRight n (rw,rh) pt = map fn ints+tableRight n (rw,rh) = liftChainF $ \pt -> map (fn pt) ints   where-    ints = iterate (+1) 0-    fn i = let (y,x) = i `divMod` n -           in displace (rw * fromIntegral x) (rh * fromIntegral (-y)) pt--+    ints    = iterate (+1) 0+    fn pt i = let (y,x) = i `divMod` n +              in displace (rw * fromIntegral x) (rh * fromIntegral (-y)) pt   --- | 'horizontal' : @ horizontal_dist -> LocChain @+-- | 'horizontalPoints' : @ horizontal_dist -> LocChain @ -- -- The chain grows right by the supplied increment. -- -- This chain is infinite. ----- \*\* WARNING \*\* - name due to be changed. Current name is --- too general for this function. ----horizontal :: Num u => u -> LocChain u-horizontal dx = iterate (displaceH dx)+horizontalPoints :: Num u => u -> LocChain u+horizontalPoints dx = liftChainF $ iterate (displaceH dx)  --- | 'vertical' : @ vertical_dist -> LocChain @+-- | 'verticalPoints' : @ vertical_dist -> LocChain @ -- -- The chain grows up by the supplied increment. -- -- This chain is infinite. ----- \*\* WARNING \*\* - name due to be changed. Current name is --- too general for this function. ----vertical :: Num u => u -> LocChain u-vertical dy = iterate (displaceV dy) +verticalPoints :: Num u => u -> LocChain u+verticalPoints dy = liftChainF $ iterate (displaceV dy)  --- | 'horizontals' : @ [horizontal_dist] -> LocChain @+-- | 'horizontalSteps' : @ [horizontal_dist] -> LocChain @ -- -- This is a @scanl@ successive displacing the start point. -- -- This chain is finite (for finite input list). ----- \*\* WARNING \*\* - name due to be changed. Current name is --- too general for this function. ----horizontals :: Num u => [u] -> LocChain u-horizontals xs = \pt -> scanl (flip displaceH) pt xs +horizontalSteps :: Num u => [u] -> LocChain u+horizontalSteps xs = liftChainF $ \pt -> scanl (flip displaceH) pt xs   --- | 'verticals' : @ [vertical_dist] -> LocChain @+-- | 'verticalSteps' : @ [vertical_dist] -> LocChain @ -- -- This is a @scanl@ successive displacing the start point. --@@ -120,7 +116,40 @@ -- \*\* WARNING \*\* - name due to be changed. Current name is  -- too general for this function.  ---verticals :: Num u => [u] -> LocChain u-verticals ys = \pt -> scanl (flip displaceV) pt ys+verticalSteps :: Num u => [u] -> LocChain u+verticalSteps ys = liftChainF $ \pt -> scanl (flip displaceV) pt ys ++{-# INLINE [0] ceilingi #-}+ceilingi :: RealFrac a => a -> Int+ceilingi = ceiling+++-- | Note - horizontals are projected from the start point. The +-- horizontal component of the second point is ignored.+-- +-- This chain is finite for well formed input.+--+innerHorizontals :: RealFrac u => u -> ConnectorChain u+innerHorizontals n = promoteR2 $ \a b -> return $ body a b+  where+    body (P2 x0 y0) (P2 x1 _) = unfoldr phi (n * fromIntegral z) +      where z                 = ceilingi $ x0 / n+            phi x | x < x1    = Just (P2 x y0, x+n)+                  | otherwise = Nothing++      ++-- | Note - verticals are projected from the start point. The +-- vertical component of the second point is ignored.+-- +-- This chain is finite for well formed input.+--+innerVerticals :: RealFrac u => u -> ConnectorChain u+innerVerticals n = promoteR2 $ \a b -> return $ body a b+  where+    body (P2 x0 y0) (P2 _ y1) = unfoldr phi (n * fromIntegral z)+      where z                 = ceilingi $ y0 / n+            phi y | y < y1    = Just (P2 x0 y, y+n)+                  | otherwise = Nothing 
src/Wumpus/Drawing/Dots/AnchorDots.hs view
@@ -57,12 +57,13 @@   ) where  -import Wumpus.Drawing.Geometry.Intersection-import Wumpus.Drawing.Geometry.Paths import Wumpus.Drawing.Dots.Marks import Wumpus.Drawing.Text.LRText -import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.Geometry.Intersection       -- package: wumpus-basic+import Wumpus.Basic.Geometry.Paths+import Wumpus.Basic.Geometry.Quadrant+import Wumpus.Basic.Kernel                 import Wumpus.Core                              -- package: wumpus-core @@ -83,8 +84,6 @@                               , radial_anchor   :: Radian   -> Point2 u                               , cardinal_anchor :: Cardinal -> Point2 u } -data Cardinal = NN | NE | EE | SE | SS | SW | WW | NW-  deriving (Eq,Show)   type instance DUnit (DotAnchor u) = u @@ -95,53 +94,53 @@    radialAnchor theta (DotAnchor _ ra _) = ra theta  instance CardinalAnchor (DotAnchor u) where-   north (DotAnchor _ _ c1) = c1 NN-   south (DotAnchor _ _ c1) = c1 SS-   east  (DotAnchor _ _ c1) = c1 EE-   west  (DotAnchor _ _ c1) = c1 WW+   north (DotAnchor _ _ c1) = c1 NORTH+   south (DotAnchor _ _ c1) = c1 SOUTH+   east  (DotAnchor _ _ c1) = c1 EAST+   west  (DotAnchor _ _ c1) = c1 WEST    instance CardinalAnchor2 (DotAnchor u) where-   northeast (DotAnchor _ _ c1) = c1 NE-   southeast (DotAnchor _ _ c1) = c1 SE-   southwest (DotAnchor _ _ c1) = c1 SW-   northwest (DotAnchor _ _ c1) = c1 NW+   northeast (DotAnchor _ _ c1) = c1 NORTH_EAST+   southeast (DotAnchor _ _ c1) = c1 SOUTH_EAST+   southwest (DotAnchor _ _ c1) = c1 SOUTH_WEST+   northwest (DotAnchor _ _ c1) = c1 NORTH_WEST   radialCardinal :: Floating u => u -> Point2 u -> Cardinal -> Point2 u-radialCardinal rad ctr NN = ctr .+^ (avec (pi/2)     rad) -radialCardinal rad ctr NE = ctr .+^ (avec (pi/4)     rad) -radialCardinal rad ctr EE = ctr .+^ (avec  0         rad) -radialCardinal rad ctr SE = ctr .+^ (avec (7/4 * pi) rad) -radialCardinal rad ctr SS = ctr .+^ (avec (6/4 * pi) rad) -radialCardinal rad ctr SW = ctr .+^ (avec (5/4 * pi) rad) -radialCardinal rad ctr WW = ctr .+^ (avec  pi        rad) -radialCardinal rad ctr NW = ctr .+^ (avec (3/4 * pi) rad) +radialCardinal rad ctr NORTH        = ctr .+^ (avec (pi/2)     rad) +radialCardinal rad ctr NORTH_EAST   = ctr .+^ (avec (pi/4)     rad) +radialCardinal rad ctr EAST         = ctr .+^ (avec  0         rad) +radialCardinal rad ctr SOUTH_EAST   = ctr .+^ (avec (7/4 * pi) rad) +radialCardinal rad ctr SOUTH        = ctr .+^ (avec (6/4 * pi) rad) +radialCardinal rad ctr SOUTH_WEST   = ctr .+^ (avec (5/4 * pi) rad) +radialCardinal rad ctr WEST         = ctr .+^ (avec  pi        rad) +radialCardinal rad ctr NORTH_WEST   = ctr .+^ (avec (3/4 * pi) rad)    -- Rectangle cardinal points are at \"middles and corners\". --  rectCardinal :: Floating u => u ->  u -> Point2 u -> Cardinal -> Point2 u-rectCardinal _  hh ctr NN = ctr .+^ (vvec hh) -rectCardinal hw hh ctr NE = ctr .+^ (vec  hw     hh) -rectCardinal hw _  ctr EE = ctr .+^ (hvec hw) -rectCardinal hw hh ctr SE = ctr .+^ (vec  hw    (-hh)) -rectCardinal _  hh ctr SS = ctr .+^ (vvec (-hh)) -rectCardinal hw hh ctr SW = ctr .+^ (vec  (-hw) (-hh) )-rectCardinal hw _  ctr WW = ctr .+^ (hvec (-hw)) -rectCardinal hw hh ctr NW = ctr .+^ (vec  (-hw)  hh) +rectCardinal _  hh ctr NORTH        = ctr .+^ (vvec hh) +rectCardinal hw hh ctr NORTH_EAST   = ctr .+^ (vec  hw     hh) +rectCardinal hw _  ctr EAST         = ctr .+^ (hvec hw) +rectCardinal hw hh ctr SOUTH_EAST   = ctr .+^ (vec  hw    (-hh)) +rectCardinal _  hh ctr SOUTH        = ctr .+^ (vvec (-hh)) +rectCardinal hw hh ctr SOUTH_WEST   = ctr .+^ (vec  (-hw) (-hh) )+rectCardinal hw _  ctr WEST         = ctr .+^ (hvec (-hw)) +rectCardinal hw hh ctr NORTH_WEST   = ctr .+^ (vec  (-hw)  hh)   polyCardinal :: Floating u => (Radian -> Point2 u) -> Cardinal -> Point2 u-polyCardinal f NN = f (0.5  * pi)-polyCardinal f NE = f (0.25 * pi) -polyCardinal f EE = f 0 -polyCardinal f SE = f (1.75 * pi) -polyCardinal f SS = f (1.5  * pi) -polyCardinal f SW = f (1.25 * pi)-polyCardinal f WW = f pi -polyCardinal f NW = f (0.75 * pi) +polyCardinal f NORTH                = f (0.5  * pi)+polyCardinal f NORTH_EAST           = f (0.25 * pi) +polyCardinal f EAST                 = f 0 +polyCardinal f SOUTH_EAST           = f (1.75 * pi) +polyCardinal f SOUTH                = f (1.5  * pi) +polyCardinal f SOUTH_WEST           = f (1.25 * pi)+polyCardinal f WEST                 = f pi +polyCardinal f NORTH_WEST           = f (0.75 * pi)    @@ -151,17 +150,18 @@               , radial_anchor   = fn                 , cardinal_anchor = rectCardinal hw hh ctr }   where-    fn theta =  maybe ctr id $ findIntersect ctr theta -                             $ rectangleLines ctr hw hh+    fn theta =  displaceVec (rectRadialVector hw hh theta) ctr  -polygonAnchor :: (Real u, Floating u) => [Point2 u] -> Point2 u -> DotAnchor u+polygonAnchor :: (Real u, Floating u, FromPtSize u) +              => [Point2 u] -> Point2 u -> DotAnchor u polygonAnchor ps ctr =      DotAnchor { center_anchor   = ctr               , radial_anchor   = fn                 , cardinal_anchor = polyCardinal fn }   where-    fn theta =  maybe ctr id $ findIntersect ctr theta $ polygonLines ps+    fn theta =  maybe ctr id $ findIntersect ctr theta +                             $ polygonLineSegments ps   @@ -217,7 +217,9 @@   dotText :: (Floating u, Real u, FromPtSize u) => String -> DotLocImage u -dotText ss = fmap (bimapL bboxRectAnchor) (ctrCenterLine ss)+dotText ss = fmap (bimapL bboxRectAnchor) (textAlignCenter ss)++-- Note - maybe Wumpus-Basic should have a @swapAns@ function?   dotHLine :: (Floating u, FromPtSize u) => DotLocImage u
src/Wumpus/Drawing/Dots/Marks.hs view
@@ -50,10 +50,10 @@   ) where  -import Wumpus.Drawing.Geometry.Paths import Wumpus.Drawing.Text.LRText -import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.Geometry.Paths              -- package: wumpus-basic+import Wumpus.Basic.Kernel          import Wumpus.Core                              -- package: wumpus-core @@ -89,7 +89,7 @@   markText :: (Real u, Floating u, FromPtSize u) => String -> LocGraphic u-markText ss = fmap (replaceL uNil) $ ctrCenterLine ss+markText ss = fmap (replaceL uNil) $ textAlignCenter ss   @@ -97,7 +97,7 @@ -- | Supplied point is the center. -- axialLine :: Fractional u => Vec2 u -> LocGraphic u-axialLine v = moveStartPoint (\ctr -> ctr .-^ (0.5 *^ v)) (straightLine v)+axialLine v = moveStart (\ctr -> ctr .-^ (0.5 *^ v)) (straightLine v)   markHLine :: (Fractional u, FromPtSize u) => LocGraphic u @@ -169,7 +169,7 @@ markSquare :: (Fractional u, FromPtSize u) => LocGraphic u markSquare =      lift0R1 markHeight >>= \h -> -    let d = 0.5*(-h) in moveStartPoint (displace d d) $ strokedRectangle h h+    let d = 0.5*(-h) in moveStart (displace d d) $ strokedRectangle h h       
− src/Wumpus/Drawing/Geometry/Intersection.hs
@@ -1,173 +0,0 @@-{-# OPTIONS -Wall #-}------------------------------------------------------------------------------------- |--- Module      :  Wumpus.Drawing.Geometry.Intersection--- Copyright   :  (c) Stephen Tetley 2010-2011--- License     :  BSD3------ Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>--- Stability   :  highly unstable--- Portability :  GHC------ Intersection of line to line and line to plane--- --- \*\* - WARNING \*\* - half baked. --------------------------------------------------------------------------------------module Wumpus.Drawing.Geometry.Intersection-  ( -    LineSegment(..)-  , PointSlope-  , pointSlope-  , LineEqn-  , lineEqn-  , toLineEqn-  , findIntersect-  , intersection--  , rectangleLines-  , polygonLines-  , langle--  ) -  where--import Wumpus.Core                              -- package: wumpus-core--import Data.AffineSpace                         -- package: vector-space-import Data.VectorSpace----- WARNING - This module is not very good (neither particularly --- robust, nor efficient).--- --- I really need to find an algorithm that does this properly.-----data LineSegment u = LS (Point2 u) (Point2 u)-  deriving (Eq,Ord,Show)---data PointSlope u = PointSlope -      { _point_slope_point :: Point2 u-      , _point_slope_slope :: u-      }-  deriving (Eq,Show)--pointSlope :: Fractional u => Point2 u -> Radian -> PointSlope u -pointSlope pt theta = PointSlope pt (fromRadian $ tan theta)----- | Line in equational form, i.e. @Ax + By + C = 0@.-data LineEqn u = LineEqn -      { _line_eqn_A :: !u-      , _line_eqn_B :: !u-      , _line_eqn_C :: !u -      }-  deriving (Eq,Show)--lineEqn :: Num u => Point2 u -> Point2 u -> LineEqn u-lineEqn (P2 x1 y1) (P2 x2 y2) = LineEqn a b c -  where-    a = y1 - y2-    b = x2 - x1-    c = (x1*y2) - (x2*y1)---toLineEqn :: Num u => PointSlope u -> LineEqn u-toLineEqn (PointSlope (P2 x0 y0) m) = LineEqn m (-1) ((-m) * x0 + y0)-----data IntersectionResult u = Intersects u u | Contained | NoIntersect-  deriving (Eq,Show)----- Note the uses a /plane/ so is susceptible to picking the --- wrong quadrant...----findIntersect :: (Floating u, Real u, Ord u)-               => Point2 u -> Radian -> [LineSegment u] -> Maybe (Point2 u)-findIntersect ctr ang0 = step -  where-    theta       = circularModulo ang0-    eqn         = toLineEqn $ pointSlope ctr theta-    step []     = Nothing-    step (x:xs) = case intersection x eqn of -                     Just pt | quadrantCheck theta ctr pt -> Just pt-                     _       -> step xs---quadrantCheck :: (Real u, Floating u) -              => Radian -> Point2 u -> Point2 u -> Bool-quadrantCheck theta ctr pt = theta == langle ctr pt--intersection :: (Fractional u, Ord u) -             => LineSegment u -> LineEqn u -> Maybe (Point2 u)-intersection ls@(LS p q) eqn = case intersect1 ls eqn of-    Intersects fp fq -> let t = fp / (fp-fq) in Just $ affineComb p q t -    Contained        -> Just p-    NoIntersect      -> Nothing----intersect1 :: (Num u, Ord u) -           => LineSegment u -> LineEqn u -> IntersectionResult u-intersect1 (LS p q) eqn = -     if inters fp fq then Intersects fp fq-                     else if contained fp fq then Contained else NoIntersect-  where-    inters a b    = (a < 0 && b >= 0) || (a > 0 && b <= 0)-    contained a b = a == 0 && b == 0-    fp            = lineF p eqn-    fq            = lineF q eqn- -lineF :: Num u => Point2 u -> LineEqn u -> u-lineF (P2 x y) (LineEqn a b c) = a*x + b*y + c--affineComb :: Num u => Point2 u -> Point2 u -> u -> Point2 u-affineComb p q t = p .+^ t *^ (q .-. p)-----rectangleLines :: Num u => Point2 u -> u -> u -> [LineSegment u]-rectangleLines ctr hw hh = [LS br tr, LS tr tl, LS tl bl, LS bl br]-  where-    br = ctr .+^ (vec hw    (-hh))-    tr = ctr .+^ (vec hw    hh)-    tl = ctr .+^ (vec (-hw) hh)-    bl = ctr .+^ (vec (-hw) (-hh))---polygonLines :: [Point2 u] -> [LineSegment u]-polygonLines []     = error "polygonLines - emptyList"-polygonLines (x:xs) = step x xs -  where-    step a []        = [LS a x]-    step a (b:bs)    = LS a b : step b bs------ | Calculate the counter-clockwise angle between two points --- and the x-axis.----langle :: (Floating u, Real u) => Point2 u -> Point2 u -> Radian-langle (P2 x1 y1) (P2 x2 y2) = step (x2 - x1) (y2 - y1)-  where-    -- north-east quadrant -    step x y | pve x && pve y = toRadian $ atan (y/x)          -    -    -- north-west quadrant-    step x y | pve y          = pi     - (toRadian $ atan (y / abs x))--    -- south-east quadrant-    step x y | pve x          = (2*pi) - (toRadian $ atan (abs y / x)) --    -- otherwise... south-west quadrant-    step x y                  = pi     + (toRadian $ atan (y/x))--    pve a                     = signum a >= 0
− src/Wumpus/Drawing/Geometry/Paths.hs
@@ -1,138 +0,0 @@-{-# OPTIONS -Wall #-}------------------------------------------------------------------------------------- |--- Module      :  Wumpus.Drawing.Geometry.Paths--- Copyright   :  (c) Stephen Tetley 2010-2011--- License     :  BSD3------ Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>--- Stability   :  highly unstable--- Portability :  GHC------ Paths for /elementary/ shapes - rectangles...--- --- \*\* - WARNING \*\* - half baked. --------------------------------------------------------------------------------------module Wumpus.Drawing.Geometry.Paths-  ( -    LocCoordPath-  , coordinatePrimPath--  , rectangleCoordPath-  , diamondCoordPath-  , polygonCoordPath-  , isoscelesTriangleCoordPath-  , isoscelesTrianglePoints-  , equilateralTriangleCoordPath-  , equilateralTrianglePoints-  ) -  where--import Wumpus.Core                              -- package: wumpus-core--import Data.AffineSpace                         -- package: vector-space---import Data.List ( unfoldr )----- | A functional type from /initial point/ to point list.----type LocCoordPath u = Point2 u -> [Point2 u]----- Note - extraction needs a naming scheme - extractFROM or --- extractTO? - in either case this might be queuing up --- name-clash problems.------ The Path data type will also need a similar function...---- -coordinatePrimPath :: Num u => Point2 u -> LocCoordPath u -> PrimPath u-coordinatePrimPath pt fn = go (fn pt)-  where-    go ps@(_:_) = vertexPath ps-    go []       = emptyPath pt        -- fallback----- NOTE - These functions need changing to generate LocCoordPaths...---- | Supplied point is /bottom-left/, subsequenct points are --- counter-clockise so [ bl, br, tr, tl ] .----rectangleCoordPath :: Num u => u -> u -> LocCoordPath u-rectangleCoordPath w h bl = [ bl, br, tr, tl ]-  where-    br = bl .+^ hvec w-    tr = br .+^ vvec h-    tl = bl .+^ vvec h ------ | 'diamondPath' : @ half_width * half_height * center_point -> PrimPath @----diamondCoordPath :: Num u => u -> u -> LocCoordPath u-diamondCoordPath hw hh ctr = [ s,e,n,w ]-  where-    s     = ctr .+^ vvec (-hh)-    e     = ctr .+^ hvec hw-    n     = ctr .+^ vvec hh-    w     = ctr .+^ hvec (-hw)-    ---- | 'polygonCoordPath' : @ num_points * radius * center -> [point] @ ----polygonCoordPath :: Floating u => Int -> u -> LocCoordPath u-polygonCoordPath n radius ctr = unfoldr phi (0,(pi*0.5))-  where-    theta = (pi*2) / fromIntegral n-    -    phi (i,ang) | i < n     = Just (ctr .+^ avec ang radius, (i+1,ang+theta))-                | otherwise = Nothing------ | @isocelesTriangle bw h pt@------ Supplied point is the centriod of the triangle. This has a --- nicer visual balance than using half-height.----isoscelesTriangleCoordPath :: Floating u => u -> u -> LocCoordPath u-isoscelesTriangleCoordPath bw h ctr = [bl,br,top]-  where-    (bl,br,top) = isoscelesTrianglePoints bw h ctr----- | @isocelesTriangle bw h pt@------ Supplied point is the centriod of the triangle. This has a --- nicer visual balance than using half-height.----isoscelesTrianglePoints :: Floating u -                        => u -> u -> Point2 u -> (Point2 u, Point2 u, Point2 u)-isoscelesTrianglePoints bw h ctr = (bl, br, top) -  where-    hw         = 0.5*bw -    theta      = atan $ h / hw-    centroid_h = hw * tan (0.5*theta)-    top        = ctr .+^ vvec (h - centroid_h)-    br         = ctr .+^ V2   hw  (-centroid_h)-    bl         = ctr .+^ V2 (-hw) (-centroid_h)----- | @ side_length * ctr -> [Points] @----equilateralTriangleCoordPath :: Floating u => u -> LocCoordPath u-equilateralTriangleCoordPath sl ctr = [bl, br, top] -  where-    (bl,br,top) = equilateralTrianglePoints sl ctr--equilateralTrianglePoints :: Floating u -                          => u -> Point2 u -> (Point2 u, Point2 u, Point2 u)-equilateralTrianglePoints sl = isoscelesTrianglePoints sl h-  where-    h = sl * sin (pi/3)-
+ src/Wumpus/Drawing/Grids.hs view
@@ -0,0 +1,67 @@+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Grids+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Drawing grids+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Grids+  ( +    grid+  , interiorGrid++  ) where++import Wumpus.Drawing.Chains++import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Core                              -- package: wumpus-core++++grid :: Fractional u => (Int,Int) -> u -> LocGraphic u+grid (nx,ny) incr    +    | nx < 1 || ny < 1 = emptyLocGraphic+    | otherwise        = promoteR1 $ \sw -> +        let rw      = incr * fromIntegral nx+            rh      = incr * fromIntegral ny+            xchn    = horizontalPoints incr+            ychn    = verticalPoints incr+            vline1  = straightLine (vvec rh)+            hline1  = straightLine (hvec rw)+            vlines  = unchain nx emptyLocGraphic vline1 xchn+            hlines  = unchain ny emptyLocGraphic hline1  ychn+        in (hlines `oplus` vlines `oplus` strokedRectangle rw rh) `at` sw++++-- | 'interiorGrid' : @ increment -> ConnectorGraphic @+--+-- Draw the interior lines of a grid between the /connector/ +-- points - start point is interpreted as bottom-left, end-point+-- is interpreted as top right.+--+-- The interior lines are calculated with repsect to the 0 and the +-- increment, for instance with an increment of 10 but a start +-- point @(15,0)@ lines are drawn from @(20,0), (30,0)@ etc.+--+interiorGrid :: RealFrac u => u -> ConnectorGraphic u+interiorGrid incr = promoteR2 $ \sw ne ->+    let xcc         = innerHorizontals incr+        ycc         = innerVerticals   incr+        (V2 vx vy)  = pvec sw ne+        hline1      = straightLine (hvec vx)+        vline1      = straightLine (vvec vy)+        vlines      = unconnectorChain emptyConnectorGraphic vline1 xcc+        hlines      = unconnectorChain emptyConnectorGraphic hline1 ycc+    in connect (hlines `oplus` vlines) sw ne+
src/Wumpus/Drawing/Paths.hs view
@@ -3,7 +3,7 @@ -------------------------------------------------------------------------------- -- | -- Module      :  Wumpus.Drawing.Paths--- Copyright   :  (c) Stephen Tetley 2010+-- Copyright   :  (c) Stephen Tetley 2010-2011 -- License     :  BSD3 -- -- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>@@ -11,6 +11,9 @@ -- Portability :  GHC -- -- Shim import module for Paths.+--+-- Note MonadicConstruction is not exported, this module is +-- somewhat out-of-date and needs a re-think. --  -------------------------------------------------------------------------------- @@ -20,12 +23,10 @@     module Wumpus.Drawing.Paths.Base   , module Wumpus.Drawing.Paths.Connectors   , module Wumpus.Drawing.Paths.ControlPoints-  , module Wumpus.Drawing.Paths.MonadicConstruction    ) where  import Wumpus.Drawing.Paths.Base import Wumpus.Drawing.Paths.Connectors import Wumpus.Drawing.Paths.ControlPoints-import Wumpus.Drawing.Paths.MonadicConstruction 
src/Wumpus/Drawing/Paths/Base.hs view
@@ -69,9 +69,8 @@   ) where  -import Wumpus.Drawing.Geometry.Intersection ( langle ) --- package: wumpus-basic+import Wumpus.Basic.Geometry.Base               -- package: wumpus-basic import Wumpus.Basic.Utils.JoinList ( JoinList, ViewL(..), viewl                                    , ViewR(..), viewr, cons, snoc, join ) import qualified Wumpus.Basic.Utils.JoinList as JL@@ -79,7 +78,6 @@ import Wumpus.Core                              -- package: wumpus-core  import Data.AffineSpace-import Data.VectorSpace  import Data.List ( foldl' )  @@ -175,9 +173,9 @@              in Path v p0 (JL.one $ LineSeg v p0 p1) p1     -curve :: (Floating u, Ord u)+curve :: (Floating u, Ord u, FromPtSize u)       => Point2 u -> Point2 u -> Point2 u -> Point2 u -> Path u -curve p0 p1 p2 p3 = let v = curveLength p0 p1 p2 p3+curve p0 p1 p2 p3 = let v = bezierLength (BezierCurve p0 p1 p2 p3)                     in Path v p0 (JL.one $ CurveSeg v p0 p1 p2 p3) p3  -- | A draw a /straight line/ of length 0 at the supplied point. @@ -209,7 +207,8 @@ -- 'traceCurvePoints' throws a runtime error if the supplied list -- is has less than 4 elements (start, control1, control2, end).  ---traceCurvePoints :: (Floating u, Ord u) => [Point2 u] -> Path u+traceCurvePoints :: (Floating u, Ord u, FromPtSize u) +                 => [Point2 u] -> Path u traceCurvePoints (a:b:c:d:xs) = step (curve a b c d) d xs   where     step acc p0 (x:y:z:zs) = step (acc `append` curve p0 x y z) z zs@@ -218,7 +217,7 @@ traceCurvePoints _            = error "tracePointsCurve - less than 4 elems."  -curveByAngles :: (Floating u, Ord u) +curveByAngles :: (Floating u, Ord u, FromPtSize u)                => Point2 u -> Radian -> Radian -> Point2 u -> Path u curveByAngles start cin cout end = curve start (start .+^ v1) (end .+^ v2) end   where@@ -252,75 +251,7 @@   ------------------------------------------------------------------------------------ Curve length -data StrictCurve u = Curve !(Point2 u) !(Point2 u) !(Point2 u) !(Point2 u)--curveLength :: (Floating u, Ord u)      -            => Point2 u -> Point2 u -> Point2 u -> Point2 u -> u-curveLength p0 p1 p2 p3 = gravesenLength 0.1 $ Curve p0 p1 p2 p3----- | Jens Gravesen\'s bezier arc-length approximation. ------ Note this implementation is parametrized on error tolerance.----gravesenLength :: (Floating u, Ord u) => u -> StrictCurve u -> u-gravesenLength err_tol crv = step crv where-  step c = let l1 = ctrlPolyLength c-               l0 = cordLength c-           in if   l1-l0 > err_tol-              then let (a,b) = subdivide c in step a + step b-              else 0.5*l0 + 0.5*l1---ctrlPolyLength :: Floating u => StrictCurve u -> u-ctrlPolyLength (Curve p0 p1 p2 p3) = len p0 p1 + len p1 p2 + len p2 p3-  where-    len pa pb = vlength $ pvec pa pb--cordLength :: Floating u => StrictCurve u -> u-cordLength (Curve p0 _ _ p3) = vlength $ pvec p0 p3----- | mid-point between two points----pointMidpoint :: Fractional u => Point2 u -> Point2 u -> Point2 u-pointMidpoint p0 p1 = p0 .+^ v1 ^/ 2 where v1 = p1 .-. p0----- | Curve subdivision via de Casteljau\'s algorithm.----subdivide :: Fractional u -          => StrictCurve u -> (StrictCurve u, StrictCurve u)-subdivide (Curve p0 p1 p2 p3) =-    (Curve p0 p01 p012 p0123, Curve p0123 p123 p23 p3)-  where-    p01   = pointMidpoint p0    p1-    p12   = pointMidpoint p1    p2-    p23   = pointMidpoint p2    p3-    p012  = pointMidpoint p01   p12-    p123  = pointMidpoint p12   p23-    p0123 = pointMidpoint p012  p123---- | subdivide with an affine weight along the line...----subdividet :: Real u-           => u -> StrictCurve u -> (StrictCurve u, StrictCurve u)-subdividet t (Curve p0 p1 p2 p3) = -    (Curve p0 p01 p012 p0123, Curve p0123 p123 p23 p3)-  where-    p01   = affineCombination t p0    p1-    p12   = affineCombination t p1    p2-    p23   = affineCombination t p2    p3-    p012  = affineCombination t p01   p12-    p123  = affineCombination t p12   p23-    p0123 = affineCombination t p012  p123--affineCombination :: Real u => u -> Point2 u -> Point2 u -> Point2 u-affineCombination a p1 p2 = p1 .+^ a *^ (p2 .-. p1)- -------------------------------------------------------------------------------- -- tips  @@ -372,9 +303,11 @@ shortenSegL n (LineSeg  u p0 p1)        =      LineSeg  (u-n) (shortenLineL n p0 p1) p1 -shortenSegL n (CurveSeg u p0 p1 p2 p3)  = -    let (Curve p0' p1' p2' p3') = snd $ subdividet (n/u) (Curve p0 p1 p2 p3)-    in CurveSeg (u-n) p0' p1' p2' p3'+shortenSegL n (CurveSeg u p0 p1 p2 p3)  = CurveSeg (u-n) q0 q1 q2 q3+  where+    (BezierCurve q0 q1 q2 q3) = snd $ subdividet (n/u) +                                                 (BezierCurve p0 p1 p2 p3)+        shortenLineL :: (Real u, Floating u) @@ -419,9 +352,11 @@ shortenSegR n (LineSeg  u p0 p1)        =      LineSeg  (u-n) p0 (shortenLineR n p0 p1)  -shortenSegR n (CurveSeg u p0 p1 p2 p3)  = -    let (Curve p0' p1' p2' p3') = fst $ subdividet ((u-n)/u) (Curve p0 p1 p2 p3)-    in CurveSeg (u-n) p0' p1' p2' p3'+shortenSegR n (CurveSeg u p0 p1 p2 p3)  = CurveSeg (u-n) q0 q1 q2 q3+  where+    (BezierCurve q0 q1 q2 q3) = fst $ subdividet ((u-n)/u) +                                                 (BezierCurve p0 p1 p2 p3)+        shortenLineR :: (Real u, Floating u) @@ -555,14 +490,14 @@ -- longer than half of /d/ (d - being the distance between the  -- /truncated/ points and the corner). ---cornerCurve :: (Real u, Floating u) +cornerCurve :: (Real u, Floating u, FromPtSize u)              => Point2 u -> Point2 u -> Point2 u -> Path u cornerCurve p1 p2 p3 = curve p1 cp1 cp2 p3   where     len1 = 0.6 *  (vlength $ pvec p1 p2)     len2 = 0.6 *  (vlength $ pvec p3 p2)-    cp1  = p1 .+^ (avec (langle p1 p2) len1)-    cp2  = p3 .+^ (avec (langle p3 p2) len2)+    cp1  = p1 .+^ (avec (lineAngle p1 p2) len1)+    cp2  = p3 .+^ (avec (lineAngle p3 p2) len2)   -- | 'roundTrail' : @ rounding_distance * [point] -> Path @@@ -580,7 +515,7 @@ -- If the list has one element /the null path/ is built, if the  -- list has two elements a straight line is built. ---roundTrail :: (Real u, Floating u) +roundTrail :: (Real u, Floating u, FromPtSize u)             => u -> [Point2 u] -> Path u  roundTrail _ []             = error "roundTrail - empty list." roundTrail _ [a]            = pathZero a@@ -599,7 +534,7 @@ -- Note - the starting point is moved, this function is for  -- closed, rounded paths. ---lineCurveTrail :: (Real u, Floating u) +lineCurveTrail :: (Real u, Floating u, FromPtSize u)                 => u -> Point2 u -> Point2 u -> Point2 u -> Path u lineCurveTrail u a b c = line p1 p2 `append` cornerCurve p2 b p3   where@@ -620,8 +555,8 @@ -- empty. If the list has one element /the null path/ is built,  -- if the list has two elements a straight line is built. ---roundInterior :: (Real u, Floating u) -           => u -> [Point2 u] -> Path u +roundInterior :: (Real u, Floating u, FromPtSize u) +              => u -> [Point2 u] -> Path u  roundInterior _ []             = error "roundEveryInterior - empty list." roundInterior _ [a]            = pathZero a roundInterior _ [a,b]          = line a b@@ -640,7 +575,7 @@ -- Note - draws a straight line from the starting point - this is  -- the first step of an interior (non-closed) rounded path ---lineCurveInter1 :: (Real u, Floating u) +lineCurveInter1 :: (Real u, Floating u, FromPtSize u)                  => u -> Point2 u -> Point2 u -> Point2 u -> (Path u, Point2 u) lineCurveInter1 u a b c =      (line a p2 `append` cornerCurve p2 b p3, p3)
src/Wumpus/Drawing/Paths/Connectors.hs view
@@ -184,7 +184,8 @@ -- -- @u@ is the altitude of the triangle. ---connIsoscelesCurve :: (Real u, Floating u) => u -> ConnectorPath u +connIsoscelesCurve :: (Real u, Floating u, FromPtSize u) +                   => u -> ConnectorPath u  connIsoscelesCurve u = promoteR2 $ \ p0 p1 ->     let control_pt  = midpointIsosceles u p0 p1     in pure $ traceCurvePoints [p0, control_pt, control_pt, p1]@@ -196,7 +197,8 @@ -- The two Bezier control points take the /top/ corners. The -- curve tends to be very deep. -- -connSquareCurve :: (Real u, Floating u) => ConnectorPath u +connSquareCurve :: (Real u, Floating u, FromPtSize u) +                => ConnectorPath u  connSquareCurve = promoteR2 $ \ p0 p1 ->     let (cp0,cp1) = squareFromBasePoints p0 p1     in pure $ traceCurvePoints [p0, cp0, cp1, p1]@@ -210,7 +212,8 @@ --  -- (Underneath is modulo the direction, of course). -- -connUSquareCurve :: (Real u, Floating u) => ConnectorPath u +connUSquareCurve :: (Real u, Floating u, FromPtSize u) +                 => ConnectorPath u  connUSquareCurve = promoteR2 $ \ p0 p1 ->      let (cp0,cp1) = usquareFromBasePoints p0 p1     in pure $ traceCurvePoints [p0, cp0, cp1, p1]@@ -220,7 +223,8 @@ -- -- Form a curve inside a trapeziod. -- -connTrapezoidCurve :: (Real u, Floating u) => u -> u -> ConnectorPath u +connTrapezoidCurve :: (Real u, Floating u, FromPtSize u) +                   => u -> u -> ConnectorPath u  connTrapezoidCurve u ratio_to_base = promoteR2 $ \p0 p1 ->      let (cp0,cp1)  = trapezoidFromBasePoints u ratio_to_base p0 p1     in pure $ traceCurvePoints [p0, cp0, cp1, p1]@@ -229,7 +233,8 @@ -- | Make a curve within a square, following the corner points as -- a Z. ---connZSquareCurve :: (Real u, Floating u) => ConnectorPath u +connZSquareCurve :: (Real u, Floating u, FromPtSize u) +                 => ConnectorPath u  connZSquareCurve = promoteR2 $ \p0 p1 ->      let (cp0,cp1)  = squareFromCornerPoints p0 p1     in pure $ traceCurvePoints [p0,cp0,cp1,p1]@@ -240,7 +245,8 @@ -- The order of tracing flips the control points, so this is an -- /underneath/ version of 'connZSquareCurve'. -- -connUZSquareCurve :: (Real u, Floating u) => ConnectorPath u +connUZSquareCurve :: (Real u, Floating u, FromPtSize u) +                  => ConnectorPath u  connUZSquareCurve = promoteR2 $ \ p0 p1 ->      let (cp0,cp1)  = squareFromCornerPoints p0 p1     in pure $ traceCurvePoints [p0,cp1,cp0,p1]
src/Wumpus/Drawing/Paths/MonadicConstruction.hs view
@@ -127,7 +127,7 @@   -bezierto :: (Floating u, Ord u) +bezierto :: (Floating u, Ord u, FromPtSize u)           => Point2 u -> Point2 u -> Point2 u -> PathM u () bezierto c1 c2 ep = PathM $ \(St p0 ac) ->      ((), St ep (ac `snocH` curve p0 c1 c2 ep))@@ -139,7 +139,7 @@ --  -curveto :: (Floating u, Ord u) +curveto :: (Floating u, Ord u, FromPtSize u)          => Radian -> Radian -> Point2 u -> PathM u () curveto cin cout end = PathM $ \(St p0 ac) ->      let seg  = curveByAngles p0 cin cout end 
src/Wumpus/Drawing/Shapes.hs view
@@ -20,12 +20,29 @@   , module Wumpus.Drawing.Shapes.Circle   , module Wumpus.Drawing.Shapes.Diamond   , module Wumpus.Drawing.Shapes.Ellipse+  , module Wumpus.Drawing.Shapes.InvSemicircle+  , module Wumpus.Drawing.Shapes.InvSemiellipse+  , module Wumpus.Drawing.Shapes.InvTriangle+  , module Wumpus.Drawing.Shapes.Parallelogram   , module Wumpus.Drawing.Shapes.Rectangle-+  , module Wumpus.Drawing.Shapes.Semicircle+  , module Wumpus.Drawing.Shapes.Semiellipse+  , module Wumpus.Drawing.Shapes.Trapezium+  , module Wumpus.Drawing.Shapes.Triangle   ) where  import Wumpus.Drawing.Shapes.Base import Wumpus.Drawing.Shapes.Circle import Wumpus.Drawing.Shapes.Diamond import Wumpus.Drawing.Shapes.Ellipse+import Wumpus.Drawing.Shapes.InvSemicircle+import Wumpus.Drawing.Shapes.InvSemiellipse+import Wumpus.Drawing.Shapes.InvTriangle+import Wumpus.Drawing.Shapes.Parallelogram import Wumpus.Drawing.Shapes.Rectangle+import Wumpus.Drawing.Shapes.Semicircle+import Wumpus.Drawing.Shapes.Semiellipse+import Wumpus.Drawing.Shapes.Trapezium+import Wumpus.Drawing.Shapes.Triangle++
src/Wumpus/Drawing/Shapes/Base.hs view
@@ -4,7 +4,7 @@  -------------------------------------------------------------------------------- -- |--- Module      :  Wumpus.Drawing.Shapes.Base2+-- Module      :  Wumpus.Drawing.Shapes.Base -- Copyright   :  (c) Stephen Tetley 2010-2011 -- License     :  BSD3 --@@ -21,59 +21,144 @@   (   -    LocShape-  , intoLocShape+    Shape+  , DShape++  , makeShape   , strokedShape   , filledShape   , borderedShape+  , rstrokedShape+  , rfilledShape+  , rborderedShape    , roundCornerShapePath +  , updatePathAngle+  , setDecoration+   , ShapeCTM   , makeShapeCTM   , ctmCenter   , ctmAngle-  , projectPoint-+  , displaceCenter      ) where -import Wumpus.Basic.Kernel import Wumpus.Drawing.Paths +import Wumpus.Basic.Kernel                      -- package: wumpus-basic import Wumpus.Core                              -- package: wumpus-core  +import Data.AffineSpace                         -- package: vector-space+ import Control.Applicative  -type LocShape u a = LocCF u (a, Path u)+-- | Shape is a record of three /LocTheta/ functions - +-- functions /from Point and Angle to answer/. +--+-- The @shape_path_fun@ returns a path. When the Shape is drawn, +-- the rendering function (@strokedShape@, etc.) uses the path for +-- drawing and returns the polymorphic answer @a@ of the +-- @shape_ans_fun@. Lastly the @shape_decoration@ function can +-- instantiated to add decoration (e.g. text) to the Shape as it +-- is rendered.+--+-- The @a@ of the @shape_ans_fun@ represents some concrete shape +-- object (e.g. a Rectangle, Triangle etc.). Crucial for shape +-- objects is that they support Anchors - this allows connectors +-- to address specific locations on the Shape border so +-- \"node and link\" diagrams can be made easily.+--+data Shape u a = Shape +      { shape_ans_fun     :: LocThetaCF u a+      , shape_path_fun    :: LocThetaCF u (Path u) +      , shape_decoration  :: LocThetaGraphic u+      }  -intoLocShape :: LocCF u a -> LocCF u (Path u) -> LocCF u (a,Path u)-intoLocShape = liftA2 (,)+type DShape a = Shape Double a -strokedShape :: Num u => LocShape u a -> LocImage u a-strokedShape mf = -   promoteR1 $ \pt -> -     (mf `at` pt) >>= \(a,spath) -> -     intoImage (pure a) (closedStroke $ toPrimPath spath)+type instance DUnit (Shape u a) = u  -filledShape :: Num u => LocShape u a -> LocImage u a-filledShape mf = -   promoteR1 $ \pt -> -     (mf `at` pt) >>= \(a,spath) -> -     intoImage (pure a) (filledPath $ toPrimPath spath)+-------------------------------------------------------------------------------- +instance Functor (Shape u) where+  fmap f = (\s i -> s { shape_ans_fun = fmap f i }) +             <*> shape_ans_fun -borderedShape :: Num u => LocShape u a -> LocImage u a-borderedShape mf = -   promoteR1 $ \pt -> -     (mf `at` pt) >>= \(a,spath) -> -     intoImage (pure a) (borderedPath $ toPrimPath spath) +-- Note - there are no instances of Applicative, Monad, +-- DrawingCtxM... so Shapes cannot have localized drawing props.+--+-- @localize@ must be performed in the context of @strokeShape@, +-- @fillShape@ etc.+--++++--------------------------------------------------------------------------------+++makeShape :: Num u => LocThetaCF u a -> LocThetaCF u (Path u) -> Shape u a+makeShape f g = Shape { shape_ans_fun    = f+                      , shape_path_fun   = g+                      , shape_decoration = emptyLocThetaGraphic+                      }+++++strokedShape :: Num u => Shape u a -> LocImage u a+strokedShape = shapeToLoc closedStroke+++filledShape :: Num u => Shape u a -> LocImage u a+filledShape = shapeToLoc filledPath+++borderedShape :: Num u => Shape u a -> LocImage u a+borderedShape = shapeToLoc borderedPath+++shapeToLoc :: Num u +           => (PrimPath u -> Graphic u) -> Shape u a -> LocImage u a+shapeToLoc pathF sh = promoteR1 $ \pt -> +    atRot (shape_ans_fun sh)  pt 0 >>= \a -> +    atRot (shape_path_fun sh) pt 0 >>= \spath -> +    let g1 = pathF $ toPrimPath spath +        g2 = atRot (shape_decoration sh) pt 0 +    in intoImage (pure a) (g1 `oplus` g2)++++rstrokedShape :: Num u => Shape u a -> LocThetaImage u a+rstrokedShape = shapeToLocTheta closedStroke+++rfilledShape :: Num u => Shape u a -> LocThetaImage u a+rfilledShape = shapeToLocTheta filledPath+++rborderedShape :: Num u => Shape u a -> LocThetaImage u a+rborderedShape = shapeToLocTheta borderedPath+++shapeToLocTheta :: Num u +                => (PrimPath u -> Graphic u) -> Shape u a -> LocThetaImage u a+shapeToLocTheta pathF sh = promoteR2 $ \pt theta -> +    atRot (shape_ans_fun sh)  pt theta >>= \a -> +    atRot (shape_path_fun sh) pt theta >>= \spath -> +    let g1 = pathF $ toPrimPath spath +        g2 = atRot (shape_decoration sh) pt theta+    in intoImage (pure a) (g1 `oplus` g2)+++ -- | Draw the shape path with round corners. --  roundCornerShapePath :: (Real u, Floating u, FromPtSize u) @@ -82,8 +167,35 @@     if sz == 0 then return (traceLinePoints xs)                 else return (roundTrail  sz xs) +-- | The path angle can be modified. This allows /inverse/ +-- versions of shapes (e.g. InvTriangle) to be made by+-- wrapping a base Shape but rotating the path prior to drawing +-- it.+-- +-- Only the Path needs rotating, the decoration takes the original +-- angle. The anchors are typically implemented by rotating the +-- correspoding anchor of the wrapped Shape about its center.+-- +updatePathAngle :: (Radian -> Radian) -> Shape u a -> Shape u a+updatePathAngle f = +    (\s i -> s { shape_path_fun = moveTheta (circularModulo . f) i})+      <*> shape_path_fun +setDecoration :: LocThetaGraphic u -> Shape u a -> Shape u a+setDecoration gf = (\s -> s { shape_decoration = gf }) ++++-- For Wumpus-Basic...+-- | Move the /rotation/ of a LocThetaImage with the supplied +-- displacement function.+--+moveTheta :: (Radian -> Radian) -> LocThetaCF u a -> LocThetaCF u a+moveTheta f ma = promoteR2 $ \pt theta -> apply2R2 ma pt (f theta)+++ -------------------------------------------------------------------------------- -- CTM @@ -102,13 +214,11 @@  type instance DUnit (ShapeCTM u) = u -makeShapeCTM :: Num u => Point2 u -> ShapeCTM u-makeShapeCTM pt = ShapeCTM { ctm_center   = pt-                           , ctm_scale_x  = 1-                           , ctm_scale_y  = 1-                           , ctm_rotation = 0 }--+makeShapeCTM :: Num u => Point2 u -> Radian -> ShapeCTM u+makeShapeCTM pt ang = ShapeCTM { ctm_center   = pt+                               , ctm_scale_x  = 1+                               , ctm_scale_y  = 1+                               , ctm_rotation = ang }   instance Num u => Scale (ShapeCTM u) where@@ -141,11 +251,13 @@ ctmAngle = ctm_rotation  --projectPoint :: (Real u, Floating u) => Point2 u -> ShapeCTM u  -> Point2 u-projectPoint (P2 x y) (ShapeCTM { ctm_center   = (P2 dx dy)-                                , ctm_scale_x  = sx-                                , ctm_scale_y  = sy-                                , ctm_rotation = theta     }) =-    translate dx dy $ rotate theta $ P2 (sx*x) (sy*y)-+displaceCenter :: (Real u, Floating u) => Vec2 u -> ShapeCTM u  -> Point2 u+displaceCenter v0 (ShapeCTM { ctm_center   = ctr0+                            , ctm_scale_x  = sx+                            , ctm_scale_y  = sy+                            , ctm_rotation = theta }) = ctr .+^ v+  where+    ctr = rotate theta $ scale sx sy ctr0+    v   = rotateAbout theta ctr $ scale sx sy v0+     +    
src/Wumpus/Drawing/Shapes/Circle.hs view
@@ -32,7 +32,6 @@  import Wumpus.Core                              -- package: wumpus-core -import Data.AffineSpace                         -- package: vector-space   import Control.Applicative @@ -45,49 +44,54 @@       { circ_ctm    :: ShapeCTM u       , circ_radius :: !u        }-  deriving (Eq,Show)    type DCircle = Circle Double  type instance DUnit (Circle u) = u  -+--------------------------------------------------------------------------------+-- Affine trans -mapCircleCTM :: (ShapeCTM u -> ShapeCTM u) -> Circle u -> Circle u-mapCircleCTM f = (\s i -> s { circ_ctm = f i }) <*> circ_ctm+mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Circle u -> Circle u+mapCTM f = (\s i -> s { circ_ctm = f i }) <*> circ_ctm  instance Num u => Scale (Circle u) where-  scale sx sy = mapCircleCTM (scale sx sy)+  scale sx sy = mapCTM (scale sx sy)   instance Rotate (Circle u) where-  rotate ang = mapCircleCTM (rotate ang)+  rotate ang = mapCTM (rotate ang)                     instance (Real u, Floating u) => RotateAbout (Circle u) where-  rotateAbout ang pt = mapCircleCTM (rotateAbout ang pt)+  rotateAbout ang pt = mapCTM (rotateAbout ang pt)   instance Num u => Translate (Circle u) where-  translate dx dy = mapCircleCTM (translate dx dy)+  translate dx dy = mapCTM (translate dx dy)  +--------------------------------------------------------------------------------+-- Anchors -runCircle :: (u -> ShapeCTM u -> a) -> Circle u -> a-runCircle fn (Circle { circ_ctm = ctm, circ_radius = radius }) = -    fn radius ctm+runDisplaceCenter :: (Real u, Floating u) +                  => (u -> Vec2 u) -> Circle u -> Point2 u+runDisplaceCenter fn (Circle { circ_ctm    = ctm+                             , circ_radius = radius }) = +    displaceCenter (fn radius) ctm  + instance (Real u, Floating u) => CenterAnchor (Circle u) where-  center = runCircle (\_ -> ctmCenter)+  center = runDisplaceCenter $ \_ -> V2 0 0    instance (Real u, Floating u) => CardinalAnchor (Circle u) where-  north = runCircle $ \r -> projectPoint $ P2 0    r-  south = runCircle $ \r -> projectPoint $ P2 0  (-r)-  east  = runCircle $ \r -> projectPoint $ P2 r    0-  west  = runCircle $ \r -> projectPoint $ P2 (-r) 0+  north = runDisplaceCenter $ \r -> V2 0    r+  south = runDisplaceCenter $ \r -> V2 0  (-r)+  east  = runDisplaceCenter $ \r -> V2 r    0+  west  = runDisplaceCenter $ \r -> V2 (-r) 0   instance (Real u, Floating u) => CardinalAnchor2 (Circle u) where@@ -98,29 +102,35 @@   instance (Real u, Floating u) => RadialAnchor (Circle u) where-  radialAnchor theta = runCircle $ \r -> projectPoint $ zeroPt .+^ avec theta r-+  radialAnchor ang = runDisplaceCenter $ \r -> avec ang r    +--------------------------------------------------------------------------------+-- Construction --- | 'circle'  : @ radius -> shape @+-- | 'circle'  : @ radius -> Shape @ ---circle :: (Real u, Floating u) => u -> LocShape u (Circle u)-circle radius = intoLocShape (mkCircle radius) (mkCirclePath radius)+circle :: (Real u, Floating u, FromPtSize u) +       => u -> Shape u (Circle u)+circle radius = makeShape (mkCircle radius) (mkCirclePath radius)             -mkCircle :: Num u => u -> LocCF u (Circle u)-mkCircle radius = promoteR1 $ \ctr -> -    pure $ Circle { circ_ctm = makeShapeCTM ctr, circ_radius = radius }-+mkCircle :: Num u => u -> LocThetaCF u (Circle u)+mkCircle radius = promoteR2 $ \ctr theta -> +    pure $ Circle { circ_ctm    = makeShapeCTM ctr theta+                  , circ_radius = radius +                  }  -mkCirclePath :: (Floating u, Ord u) => u -> LocCF u (Path u)-mkCirclePath radius = promoteR1 $ \ctr -> -    pure $ traceCurvePoints $ bezierCircle 2 radius ctr +-- Rotation (theta) can be ignored.+--+mkCirclePath :: (Floating u, Ord u, FromPtSize u) +             => u -> LocThetaCF u (Path u)+mkCirclePath radius = promoteR2 $ \ctr _ -> +    pure $ traceCurvePoints $ bezierCircle radius ctr    
src/Wumpus/Drawing/Shapes/Diamond.hs view
@@ -12,7 +12,7 @@ -- Stability   :  highly unstable -- Portability :  GHC ----- Simple shapes - rectangle, circle diamond, ellipse.+-- Diamond (rhombus). --  -------------------------------------------------------------------------------- @@ -26,17 +26,16 @@    ) where -import Wumpus.Drawing.Geometry.Intersection-import Wumpus.Drawing.Geometry.Paths import Wumpus.Drawing.Paths import Wumpus.Drawing.Shapes.Base -import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.Geometry.Base               -- package: wumpus-basic+import Wumpus.Basic.Geometry.Quadrant+import Wumpus.Basic.Geometry.Paths+import Wumpus.Basic.Kernel        import Wumpus.Core                              -- package: wumpus-core -import Data.AffineSpace                         -- package: vector-space -import Data.VectorSpace  import Control.Applicative @@ -58,39 +57,63 @@ type instance DUnit (Diamond u) = u  -mapDiamondCTM :: (ShapeCTM u -> ShapeCTM u) -> Diamond u -> Diamond u-mapDiamondCTM f = (\s i -> s { dia_ctm = f i }) <*> dia_ctm+--------------------------------------------------------------------------------+-- Affine trans +mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Diamond u -> Diamond u+mapCTM f = (\s i -> s { dia_ctm = f i }) <*> dia_ctm+ instance Num u => Scale (Diamond u) where-  scale sx sy = mapDiamondCTM (scale sx sy)+  scale sx sy = mapCTM (scale sx sy)   instance Rotate (Diamond u) where-  rotate ang = mapDiamondCTM (rotate ang)+  rotate ang = mapCTM (rotate ang)                     instance (Real u, Floating u) => RotateAbout (Diamond u) where-  rotateAbout ang pt = mapDiamondCTM (rotateAbout ang pt)+  rotateAbout ang pt = mapCTM (rotateAbout ang pt)   instance Num u => Translate (Diamond u) where-  translate dx dy = mapDiamondCTM (translate dx dy)+  translate dx dy = mapCTM (translate dx dy)   -runDiamond :: (u -> u -> ShapeCTM u  -> a) -> Diamond u -> a-runDiamond fm (Diamond { dia_ctm = ctm, dia_hw = hw, dia_hh = hh }) = -   fm hw hh ctm+--------------------------------------------------------------------------------+-- Anchors +-- | 'runDisplaceCenter' : @ ( half_width +--                           * half_height -> Vec ) * diamond -> Point @+--+runDisplaceCenter :: (Real u, Floating u) +                  => (u -> u -> Vec2 u) -> Diamond u -> Point2 u+runDisplaceCenter fn (Diamond { dia_ctm = ctm+                              , dia_hw = hw+                              , dia_hh = hh }) = +   displaceCenter (fn hw hh) ctm + instance (Real u, Floating u) => CenterAnchor (Diamond u) where-  center = runDiamond (\_ _ -> ctmCenter)+  center = runDisplaceCenter $ \_ _ -> V2 0 0 +instance (Real u, Floating u) => ApexAnchor (Diamond u) where+  apex = runDisplaceCenter $ \_  hh -> V2 0 hh++instance (Real u, Floating u) => SideMidpointAnchor (Diamond u) where+  sideMidpoint n a = step (n `mod` 4) +    where+      step 1 = midpoint (north a) (west a)+      step 2 = midpoint (west a)  (south a)+      step 3 = midpoint (south a) (east a)+      step _ = midpoint (east a)  (north a)++ instance (Real u, Floating u) => CardinalAnchor (Diamond u) where-  north = runDiamond $ \_  hh -> projectPoint $ P2 0 hh-  south = runDiamond $ \_  hh -> projectPoint $ P2 0 (-hh)-  east  = runDiamond $ \hw _  -> projectPoint $ P2 hw 0-  west  = runDiamond $ \hw _  -> projectPoint $ P2 (-hw) 0+  north = apex+  south = runDisplaceCenter $ \_  hh -> V2 0 (-hh)+  east  = runDisplaceCenter $ \hw _  -> V2 hw 0+  west  = runDisplaceCenter $ \hw _  -> V2 (-hw) 0  instance (Real u, Floating u, Fractional u) => CardinalAnchor2 (Diamond u) where   northeast x = midpoint (north x) (east x)@@ -101,52 +124,34 @@   instance (Real u, Floating u) => RadialAnchor (Diamond u) where-   radialAnchor = diamondIntersect+    radialAnchor ang = runDisplaceCenter $ \hw hh -> +                         diamondRadialVector hw hh ang  --- Utils.Intersection needs improving...  -diamondIntersect :: (Real u, Floating u) -                 => Radian -> Diamond u -> Point2 u-diamondIntersect theta (Diamond { dia_ctm = ctm, dia_hw = hw, dia_hh = hh }) = -    let ps  = diamondPoints hw hh ctm -        ctr = ctmCenter ctm-    in maybe ctr id $ findIntersect ctr theta $ polygonLines ps-    ---midpoint :: Fractional u => Point2 u -> Point2 u -> Point2 u-midpoint p1 p2 = let v = 0.5 *^ pvec p1 p2 in p1 .+^ v--+--------------------------------------------------------------------------------+-- Construction  -- | 'diamond'  : @ half_width * half_height -> shape @ -- -- Note - args might change to tull_width and full_height... -- diamond :: (Real u, Floating u, FromPtSize u) -        => u -> u -> LocShape u (Diamond u)-diamond hw hh = intoLocShape (mkDiamond hw hh) (mkDiamondPath hw hh)+        => u -> u -> Shape u (Diamond u)+diamond hw hh = makeShape (mkDiamond hw hh) (mkDiamondPath hw hh)  -mkDiamond :: Num u => u -> u -> LocCF u (Diamond u)-mkDiamond hw hh = promoteR1 $ \ctr -> -    pure $ Diamond { dia_ctm = makeShapeCTM ctr, dia_hw = hw, dia_hh = hh }+mkDiamond :: Num u => u -> u -> LocThetaCF u (Diamond u)+mkDiamond hw hh = promoteR2 $ \ctr theta -> +    pure $ Diamond { dia_ctm = makeShapeCTM ctr theta+                   , dia_hw  = hw+                   , dia_hh = hh +                   }   mkDiamondPath :: (Real u, Floating u, FromPtSize u) -              => u -> u -> LocCF u (Path u)-mkDiamondPath hw hh = promoteR1 $ \ctr -> -    roundCornerShapePath $ diamondCoordPath hw hh ctr---diamondPoints :: (Real u, Floating u) => u -> u -> ShapeCTM u -> [Point2 u]-diamondPoints hw hh ctm = map (projectPoint `flip` ctm) [ s, e, n, w ]-  where-    s = P2   0  (-hh)-    e = P2   hw    0-    n = P2   0    hh-    w = P2 (-hw)   0 --+              => u -> u -> LocThetaCF u (Path u)+mkDiamondPath hw hh = promoteR2 $ \ctr theta -> +    roundCornerShapePath $ map (rotateAbout theta ctr) +                         $ diamondCoordPath hw hh ctr
src/Wumpus/Drawing/Shapes/Ellipse.hs view
@@ -35,7 +35,6 @@  import Wumpus.Core                              -- package: wumpus-core -import Data.AffineSpace                         -- package: vector-space   import Control.Applicative @@ -57,7 +56,8 @@  type instance DUnit (Ellipse u) = u -+--------------------------------------------------------------------------------+-- Affine trans  mapEllipseCTM :: (ShapeCTM u -> ShapeCTM u) -> Ellipse u -> Ellipse u mapEllipseCTM f = (\s i -> s { ell_ctm = f i }) <*> ell_ctm@@ -78,11 +78,17 @@   translate dx dy = mapEllipseCTM (translate dx dy)  -runEllipse :: (u -> u -> ShapeCTM u  -> a) -> Ellipse u -> a-runEllipse fn (Ellipse { ell_ctm = ctm, ell_rx = rx, ell_ry = ry }) = -    fn rx ry ctm+--------------------------------------------------------------------------------+-- Anchors +runDisplaceCenter :: (Real u, Floating u) +                  => (u -> u -> Vec2 u) -> Ellipse u -> Point2 u+runDisplaceCenter fn (Ellipse { ell_ctm = ctm+                       , ell_rx  = rx+                       , ell_ry  = ry }) = +    displaceCenter (fn rx ry) ctm + -- | x_radius is the unit length. -- scaleEll :: (Scale t, Fractional u, u ~ DUnit t) => u -> u -> t -> t@@ -90,12 +96,12 @@   instance (Real u, Floating u) => CenterAnchor (Ellipse u) where-  center = runEllipse $ \_ _ -> ctmCenter+  center = runDisplaceCenter $ \_ _ -> V2 0 0   instance (Real u, Floating u) => RadialAnchor (Ellipse u) where-  radialAnchor theta = runEllipse $ \rx ry -> -    projectPoint $ scaleEll rx ry $ zeroPt .+^ avec theta rx+  radialAnchor theta = runDisplaceCenter $ \rx ry -> +                         scaleEll rx ry $ avec theta rx   instance (Real u, Floating u) => CardinalAnchor (Ellipse u) where@@ -112,23 +118,27 @@   northwest = radialAnchor (0.75*pi)  -+--------------------------------------------------------------------------------+-- Construction  -- | 'ellipse'  : @ x_radii * y_radii -> shape @ ---ellipse :: (Floating u, Ord u) => u -> u -> LocShape u (Ellipse u)-ellipse rx ry = -    intoLocShape (mkEllipse rx ry) (mkEllipsePath rx ry)+ellipse :: (Real u, Floating u, FromPtSize u, Ord u) +        => u -> u -> Shape u (Ellipse u)+ellipse rx ry = makeShape (mkEllipse rx ry) (mkEllipsePath rx ry)  -mkEllipse :: Num u => u -> u -> LocCF u (Ellipse u)-mkEllipse rx ry = promoteR1 $ \ctr -> -    pure $ Ellipse { ell_ctm = makeShapeCTM ctr, ell_rx = rx, ell_ry = ry }+mkEllipse :: Num u => u -> u -> LocThetaCF u (Ellipse u)+mkEllipse rx ry = promoteR2 $ \ctr theta -> +    pure $ Ellipse { ell_ctm = makeShapeCTM ctr theta+                   , ell_rx  = rx+                   , ell_ry  = ry +                   } --- This is wrong...----mkEllipsePath :: (Floating u, Ord u) => u -> u -> LocCF u (Path u)-mkEllipsePath rx ry = promoteR1 $ \(P2 x y) -> -    pure $ traceCurvePoints $ map (translate x y . scaleEll rx ry) -                            $ bezierCircle 2 rx zeroPt++mkEllipsePath :: (Real u, Floating u, FromPtSize u, Ord u) +              => u -> u -> LocThetaCF u (Path u)+mkEllipsePath rx ry = promoteR2 $ \pt theta -> +    pure $ traceCurvePoints $ map (rotateAbout theta pt) +                            $ bezierEllipse rx ry pt 
+ src/Wumpus/Drawing/Shapes/InvSemicircle.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.InvSemicircle+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Inverse semicircle. +-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.InvSemicircle+  ( ++    InvSemicircle+  , DInvSemicircle+  , invsemicircle++  ) where++import Wumpus.Drawing.Shapes.Base+import Wumpus.Drawing.Shapes.Semicircle++import Wumpus.Basic.Kernel                      -- package: wumpus-basic++import Wumpus.Core                              -- package: wumpus-core+++++--------------------------------------------------------------------------------+-- Inverse semicircle++newtype InvSemicircle u = InvSemicircle { getInvSemicircle :: Semicircle u }++  +type DInvSemicircle = InvSemicircle Double++type instance DUnit (InvSemicircle u) = u+++--------------------------------------------------------------------------------+-- Affine trans++mapSemicircle :: (Semicircle u -> Semicircle u) +              -> InvSemicircle u +              -> InvSemicircle u+mapSemicircle f = InvSemicircle . f . getInvSemicircle++instance Num u => Scale (InvSemicircle u) where+  scale sx sy = mapSemicircle (scale sx sy)+++instance Rotate (InvSemicircle u) where+  rotate ang = mapSemicircle (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (InvSemicircle u) where+  rotateAbout ang pt = mapSemicircle (rotateAbout ang pt)+++instance Num u => Translate (InvSemicircle u) where+  translate dx dy = mapSemicircle (translate dx dy)+++--------------------------------------------------------------------------------+-- Anchors++runRotateAnchor :: (Real u, Floating u) +                => (Semicircle u -> Point2 u) -> InvSemicircle u -> Point2 u+runRotateAnchor f (InvSemicircle a) = rotateAbout pi (center a) (f a)+++instance (Real u, Floating u) => CenterAnchor (InvSemicircle u) where+  center = center . getInvSemicircle++instance (Real u, Floating u) => ApexAnchor (InvSemicircle u) where+  apex = runRotateAnchor apex++instance (Real u, Floating u) => TopCornerAnchor (InvSemicircle u) where+  topLeftCorner  = runRotateAnchor bottomRightCorner+  topRightCorner = runRotateAnchor bottomLeftCorner++instance (Real u, Floating u) => CardinalAnchor (InvSemicircle u) where+  north = runRotateAnchor south+  south = runRotateAnchor north+  east  = runRotateAnchor west+  west  = runRotateAnchor east+++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor2 (InvSemicircle u) where+  northeast = runRotateAnchor southwest+  southeast = runRotateAnchor northwest+  southwest = runRotateAnchor northeast+  northwest = runRotateAnchor southeast++++instance (Real u, Floating u, FromPtSize u) => +    RadialAnchor (InvSemicircle u) where+  radialAnchor theta = +    runRotateAnchor (radialAnchor $ circularModulo $ pi+theta)+++--------------------------------------------------------------------------------+-- Construction++-- | 'invsemicircle'  : @ radius -> Shape @+--+invsemicircle :: (Real u, Floating u, FromPtSize u) +           => u -> Shape u (InvSemicircle u)+invsemicircle radius = +    fmap InvSemicircle $ updatePathAngle (+ pi) $ semicircle radius
+ src/Wumpus/Drawing/Shapes/InvSemiellipse.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.InvSemiellipse+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Inverse semiellipse. +-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.InvSemiellipse+  ( ++    InvSemiellipse+  , DInvSemiellipse+  , invsemiellipse++  ) where++import Wumpus.Drawing.Shapes.Base+import Wumpus.Drawing.Shapes.Semiellipse++import Wumpus.Basic.Kernel                      -- package: wumpus-basic++import Wumpus.Core                              -- package: wumpus-core+++++--------------------------------------------------------------------------------+-- Inverse semiellipse++newtype InvSemiellipse u = InvSemiellipse { getInvSemiellipse :: Semiellipse u }++  +type DInvSemiellipse = InvSemiellipse Double++type instance DUnit (InvSemiellipse u) = u+++--------------------------------------------------------------------------------+-- Affine trans++mapSemiellipse :: (Semiellipse u -> Semiellipse u) +              -> InvSemiellipse u +              -> InvSemiellipse u+mapSemiellipse f = InvSemiellipse . f . getInvSemiellipse++instance Num u => Scale (InvSemiellipse u) where+  scale sx sy = mapSemiellipse (scale sx sy)+++instance Rotate (InvSemiellipse u) where+  rotate ang = mapSemiellipse (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (InvSemiellipse u) where+  rotateAbout ang pt = mapSemiellipse (rotateAbout ang pt)+++instance Num u => Translate (InvSemiellipse u) where+  translate dx dy = mapSemiellipse (translate dx dy)+++--------------------------------------------------------------------------------+-- Anchors++runRotateAnchor :: (Real u, Floating u) +                => (Semiellipse u -> Point2 u) -> InvSemiellipse u -> Point2 u+runRotateAnchor f (InvSemiellipse a) = rotateAbout pi (center a) (f a)+++instance (Real u, Floating u) => CenterAnchor (InvSemiellipse u) where+  center = center . getInvSemiellipse++instance (Real u, Floating u, FromPtSize u) => +    ApexAnchor (InvSemiellipse u) where+  apex = runRotateAnchor apex++instance (Real u, Floating u) => TopCornerAnchor (InvSemiellipse u) where+  topLeftCorner  = runRotateAnchor bottomRightCorner+  topRightCorner = runRotateAnchor bottomLeftCorner++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor (InvSemiellipse u) where+  north = runRotateAnchor south+  south = runRotateAnchor north+  east  = runRotateAnchor west+  west  = runRotateAnchor east+++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor2 (InvSemiellipse u) where+  northeast = runRotateAnchor southwest+  southeast = runRotateAnchor northwest+  southwest = runRotateAnchor northeast+  northwest = runRotateAnchor southeast++++instance (Real u, Floating u, FromPtSize u) => +    RadialAnchor (InvSemiellipse u) where+  radialAnchor theta = +    runRotateAnchor (radialAnchor $ circularModulo $ pi+theta)+++--------------------------------------------------------------------------------+-- Construction++-- | 'invsemiellipse'  : @ rx * ry -> Shape @+--+invsemiellipse :: (Real u, Floating u, FromPtSize u) +           => u -> u -> Shape u (InvSemiellipse u)+invsemiellipse rx ry = +    fmap InvSemiellipse $ updatePathAngle (+ pi) $ semiellipse rx ry
+ src/Wumpus/Drawing/Shapes/InvTriangle.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.InvTriangle+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Inverse version of the Triangle shape.+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.InvTriangle+  ( ++    InvTriangle+  , DInvTriangle+  , invtriangle+++  ) where++import Wumpus.Drawing.Shapes.Base+import Wumpus.Drawing.Shapes.Triangle++import Wumpus.Basic.Geometry.Base               -- package: wumpus-basic+import Wumpus.Basic.Kernel++import Wumpus.Core                              -- package: wumpus-core+++++++-- Datatype++newtype InvTriangle u = InvTriangle { getInvTriangle :: Triangle u }++++type DInvTriangle = InvTriangle Double++type instance DUnit (InvTriangle u) = u+++--------------------------------------------------------------------------------+-- Affine trans++mapTriangle :: (Triangle u -> Triangle u) -> InvTriangle u -> InvTriangle u+mapTriangle f = InvTriangle . f . getInvTriangle +++instance Num u => Scale (InvTriangle u) where+  scale sx sy = mapTriangle (scale sx sy)+++instance Rotate (InvTriangle u) where+  rotate ang = mapTriangle (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (InvTriangle u) where+  rotateAbout ang pt = mapTriangle (rotateAbout ang pt)+++instance Num u => Translate (InvTriangle u) where+  translate dx dy = mapTriangle (translate dx dy)+++--------------------------------------------------------------------------------+-- Anchors++-- I think anchors should be rotated about the center by pi...++runRotateAnchor :: (Real u, Floating u) +                => (Triangle u -> Point2 u) -> InvTriangle u -> Point2 u+runRotateAnchor f (InvTriangle a) = rotateAbout pi (center a) (f a)+++instance (Real u, Floating u) => CenterAnchor (InvTriangle u) where+  center = center . getInvTriangle+++-- apex is same on InvTriangle as regular triangle++instance (Real u, Floating u) => ApexAnchor (InvTriangle u) where+  apex = runRotateAnchor apex++-- Top corners are bottom corners of the wrapped triangle.+--+instance (Real u, Floating u) => TopCornerAnchor (InvTriangle u) where+  topLeftCorner  = runRotateAnchor bottomRightCorner+  topRightCorner = runRotateAnchor bottomLeftCorner+++-- Use established points on the InvTrangle - don\'t delegate to +-- the base Triangle.+--+instance (Real u, Floating u) => SideMidpointAnchor (InvTriangle u) where+  sideMidpoint n a = step (n `mod` 3) +    where+      step 1 = midpoint (topRightCorner a) (topLeftCorner a)+      step 2 = midpoint (topLeftCorner a)  (apex a)+      step _ = midpoint (apex a)           (topRightCorner a)++++-- east and west should be parallel to the centroid.+--++instance (Real u, Floating u) => CardinalAnchor (InvTriangle u) where+  north = runRotateAnchor south+  south = runRotateAnchor north+  east  = runRotateAnchor west+  west  = runRotateAnchor east+++instance (Real u, Floating u) => CardinalAnchor2 (InvTriangle u) where+  northeast = runRotateAnchor southwest+  southeast = runRotateAnchor northwest+  southwest = runRotateAnchor northeast+  northwest = runRotateAnchor southeast++++instance (Real u, Floating u) => RadialAnchor (InvTriangle u) where+  radialAnchor theta = runRotateAnchor (radialAnchor $ circularModulo $ pi+theta)++--------------------------------------------------------------------------------+-- Construction++-- | 'invtriangle'  : @ top_base_width * height -> Triangle @+--+--+invtriangle :: (Real u, Floating u, FromPtSize u)+            => u -> u -> Shape u (InvTriangle u)+invtriangle bw h = fmap InvTriangle $ updatePathAngle (+ pi) $ triangle bw h+    +++
+ src/Wumpus/Drawing/Shapes/Parallelogram.hs view
@@ -0,0 +1,269 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.Parallelogram+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Parallelogram.+--+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.Parallelogram+  ( ++    Parallelogram+  , DParallelogram+  , parallelogram+  , zparallelogram+++  ) where++import Wumpus.Drawing.Paths+import Wumpus.Drawing.Shapes.Base++import Wumpus.Basic.Geometry.Base               -- package: wumpus-basic+import Wumpus.Basic.Geometry.Intersection+import Wumpus.Basic.Geometry.Paths+import Wumpus.Basic.Kernel++import Wumpus.Core                              -- package: wumpus-core+++import Control.Applicative+++++--------------------------------------------------------------------------------+-- Parallelogram++-- | A Paralleogram.+--+data Parallelogram u = Parallelogram +      { pll_ctm         :: ShapeCTM u+      , pll_base_width  :: !u+      , pll_height      :: !u+      , pll_base_l_ang  :: Radian+      , pll_syn_props   :: SyntheticProps u+      }+++-- | Note (center) is a line dropped from the center of the+-- paralleogram.+-- +-- > base_minor is the (center) to left corner.+-- > base_major is the (center) to right corner.+--+data SyntheticProps u = SyntheticProps+      { pll_base_minor  :: u+      , pll_base_major  :: u+      }+++type DParallelogram = Parallelogram Double++type instance DUnit (Parallelogram u) = u+++++--------------------------------------------------------------------------------+-- Affine trans++mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Parallelogram u -> Parallelogram u+mapCTM f = (\s i -> s { pll_ctm = f i }) <*> pll_ctm++instance Num u => Scale (Parallelogram u) where+  scale sx sy = mapCTM (scale sx sy)+++instance Rotate (Parallelogram u) where+  rotate ang = mapCTM (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (Parallelogram u) where+  rotateAbout ang pt = mapCTM (rotateAbout ang pt)+++instance Num u => Translate (Parallelogram u) where+  translate dx dy = mapCTM (translate dx dy)++--------------------------------------------------------------------------------+-- Anchors++-- | 'runDisplaceCenter' : @ ( half_base_width+--                           * half_height +--                           * base_minor+--                           * base_major -> Vec ) * parallelogram -> Point @+--+runDisplaceCenter :: (Real u, Floating u)+                  => (u -> u -> u -> u -> Vec2 u) -> Parallelogram u -> Point2 u+runDisplaceCenter fn (Parallelogram { pll_ctm        = ctm+                                    , pll_base_width = bw+                                    , pll_height     = h  +                                    , pll_syn_props  = syn }) = +    displaceCenter (fn (0.5 * bw) (0.5 * h) +                       (pll_base_minor syn) (pll_base_major syn)) ctm++++instance (Real u, Floating u) => CenterAnchor (Parallelogram u) where+  center = runDisplaceCenter $ \_ _ _ _ -> V2 0 0++-- top anchors swap the base minor and major...+--+instance (Real u, Floating u) => TopCornerAnchor (Parallelogram u) where+  topLeftCorner  = runDisplaceCenter $ \_ hh _ bmaj -> V2 (-bmaj) hh+  topRightCorner = runDisplaceCenter $ \_ hh bmin _ -> V2 bmin    hh++instance (Real u, Floating u) => BottomCornerAnchor (Parallelogram u) where+  bottomLeftCorner  = runDisplaceCenter $ \_ hh bmin _ -> V2 (-bmin) (-hh)+  bottomRightCorner = runDisplaceCenter $ \_ hh _ bmaj -> V2 bmaj    (-hh)++instance (Real u, Floating u) => SideMidpointAnchor (Parallelogram u) where+  sideMidpoint n a = step (n `mod` 4) +    where+      step 1 = midpoint (topRightCorner a)    (topLeftCorner a)+      step 2 = midpoint (topLeftCorner a)     (bottomLeftCorner a)+      step 3 = midpoint (bottomLeftCorner a)  (bottomRightCorner a)+      step _ = midpoint (bottomRightCorner a) (topRightCorner a)++++instance (Real u, Floating u) => CardinalAnchor (Parallelogram u) where+  north = runDisplaceCenter $ \_  hh _ _ -> V2 0 hh+  south = runDisplaceCenter $ \_  hh _ _ -> V2 0 (-hh)+  east  = runDisplaceCenter $ \hw _  _ _ -> V2 hw 0+  west  = runDisplaceCenter $ \hw _  _ _ -> V2 (-hw) 0+++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor2 (Parallelogram u) where+  northeast = pllRadialAnchor (0.25*pi)+  southeast = pllRadialAnchor (1.75*pi)+  southwest = pllRadialAnchor (1.25*pi)+  northwest = pllRadialAnchor (0.75*pi)++++instance (Real u, Floating u, FromPtSize u) => +     RadialAnchor (Parallelogram u) where+   radialAnchor = pllRadialAnchor+++-- TODO - update this to a quadrant function...+--+pllRadialAnchor :: (Real u, Floating u, FromPtSize u) +                => Radian -> Parallelogram u -> Point2 u+pllRadialAnchor theta (Parallelogram { pll_ctm       = ctm+                                     , pll_height    = h+                                     , pll_syn_props = syn }) =+    post $ findIntersect zeroPt theta $ polygonLineSegments ps+  where +    ps   = pllPoints (pll_base_minor syn) (pll_base_major syn) h+    post = \ans -> case ans of +                    Nothing       -> displaceCenter (V2 0 0) ctm+                    Just (P2 x y) -> displaceCenter (V2 x y) ctm+    ++--------------------------------------------------------------------------------+-- Construction+++-- | 'parallelogram'  : @ width * height * bottom_left_ang -> Parallelogram @+--+--+parallelogram :: (Real u, Floating u, FromPtSize u) +              => u -> u -> Radian -> Shape u (Parallelogram u)+parallelogram bw h lang =+    let props = synthesizeProps bw h lang +    in makeShape (mkParallelogram bw h lang props) +                 (mkParallelogramPath (pll_base_minor props) +                                      (pll_base_major props) h)+++-- | 'zparallelogram'  : @ base_width * height -> Parallelogram @+--+--+zparallelogram :: (Real u, Floating u, FromPtSize u) +              => u -> u -> Shape u (Parallelogram u)+zparallelogram bw h = parallelogram bw h ang+  where+    ang = d2r (60::Double)+++--------------------------------------------------------------------------------+++mkParallelogram :: (Real u, Fractional u) +                => u -> u -> Radian -> SyntheticProps u +                -> LocThetaCF u (Parallelogram u)+mkParallelogram bw h lang props = promoteR2 $ \ctr theta -> +    pure $ Parallelogram { pll_ctm          = makeShapeCTM ctr theta+                         , pll_base_width   = bw+                         , pll_height       = h+                         , pll_base_l_ang   = lang+                         , pll_syn_props    = props+                         }++-- Note - expects ang value 0 < ang < 180, though does not check...+-- +synthesizeProps :: Fractional u => u -> u -> Radian -> SyntheticProps u+synthesizeProps bw h lang +    | lang == 0.5*pi = let hw = 0.5 * bw in SyntheticProps hw hw+    | lang >  0.5*pi = less_ninety+    | otherwise      = grtr_ninety+  where+    less_ninety = let extw            = h / (fromRadian $ tan lang)+                      half_rect_width = 0.5 * (bw + extw)+                  in SyntheticProps half_rect_width (half_rect_width - extw)++    grtr_ninety = let extw            = h / (fromRadian $ tan (pi-lang))+                      half_rect_width = 0.5 * (bw + extw)+                  in SyntheticProps (half_rect_width - extw) half_rect_width++                       ++++mkParallelogramPath :: (Real u, Floating u, FromPtSize u) +                    => u -> u -> u -> LocThetaCF u (Path u)+mkParallelogramPath bw_minor bw_major h = promoteR2 $ \ctr theta -> +    roundCornerShapePath $ map (rotateAbout theta ctr) +                         $ pllPath bw_minor bw_major h ctr+++pllPath :: (Real u, Floating u) +       => u -> u -> u -> LocCoordPath u+pllPath bw_minor bw_major h (P2 x y) = [ bl, br, tr, tl ]+  where+    hh = 0.5 * h+    bl = P2 (x - bw_minor) (y - hh)+    br = P2 (x + bw_major) (y - hh)+    tl = P2 (x - bw_major) (y + hh)     -- topleft subtracts major+    tr = P2 (x + bw_minor) (y + hh)     -- topright adds minor+++pllPoints :: (Real u, Floating u) +          => u -> u -> u -> [Point2 u]+pllPoints bw_minor bw_major h = [ bl, br, tr, tl ]+  where+    hh = 0.5 * h     +    bl = P2 (-bw_minor) (-hh) +    br = P2   bw_major  (-hh)+    tl = P2 (-bw_major) hh+    tr = P2   bw_minor  hh++++
src/Wumpus/Drawing/Shapes/Rectangle.hs view
@@ -13,6 +13,9 @@ -- Portability :  GHC -- -- Rectangle shape.+--+-- Note - CardinalAnchor2 (northeast etc.) point to their radial +-- positions (this is a change since earlier versions). --  -------------------------------------------------------------------------------- @@ -25,12 +28,12 @@    ) where -import Wumpus.Drawing.Geometry.Intersection-import Wumpus.Drawing.Geometry.Paths import Wumpus.Drawing.Paths import Wumpus.Drawing.Shapes.Base -import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.Geometry.Paths              -- package: wumpus-basic+import Wumpus.Basic.Geometry.Quadrant+import Wumpus.Basic.Kernel  import Wumpus.Core                              -- package: wumpus-core @@ -39,8 +42,7 @@   ------------------------------------------------------------------------------------ Rectangle+-- Data type  data Rectangle u = Rectangle        { rect_ctm    :: ShapeCTM u@@ -55,82 +57,109 @@ type instance DUnit (Rectangle u) = u  -mapRectangleCTM :: (ShapeCTM u -> ShapeCTM u) -> Rectangle u -> Rectangle u-mapRectangleCTM f = (\s i -> s { rect_ctm = f i }) <*> rect_ctm+--------------------------------------------------------------------------------+-- Affine trans +mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Rectangle u -> Rectangle u+mapCTM f = (\s i -> s { rect_ctm = f i }) <*> rect_ctm+ instance Num u => Scale (Rectangle u) where-  scale sx sy = mapRectangleCTM (scale sx sy)+  scale sx sy = mapCTM (scale sx sy)   instance Rotate (Rectangle u) where-  rotate ang = mapRectangleCTM (rotate ang)+  rotate ang = mapCTM (rotate ang)                     instance (Real u, Floating u) => RotateAbout (Rectangle u) where-  rotateAbout ang pt = mapRectangleCTM (rotateAbout ang pt)+  rotateAbout ang pt = mapCTM (rotateAbout ang pt)   instance Num u => Translate (Rectangle u) where-  translate dx dy = mapRectangleCTM (translate dx dy)+  translate dx dy = mapCTM (translate dx dy) +--------------------------------------------------------------------------------+-- Anchors   -runRectangle :: (u -> u -> ShapeCTM u -> a) -> Rectangle u -> a-runRectangle fn (Rectangle { rect_ctm = ctm, rect_hw = hw, rect_hh = hh }) = -   fn hw hh ctm+-- | 'runDisplaceCenter' : @ ( half_width+--                           * half_height -> Vec ) * rectangle -> Point @+--+runDisplaceCenter :: (Real u, Floating u) +                  => (u -> u -> Vec2 u) -> Rectangle u -> Point2 u+runDisplaceCenter fn (Rectangle { rect_ctm = ctm+                                , rect_hw  = hw+                                , rect_hh  = hh }) = +   displaceCenter (fn hw hh) ctm + instance (Real u, Floating u) => CenterAnchor (Rectangle u) where-  center = runRectangle (\ _ _ -> ctmCenter)+  center = runDisplaceCenter $ \_ _ -> V2 0 0 +instance (Real u, Floating u) => TopCornerAnchor (Rectangle u) where+  topLeftCorner  = runDisplaceCenter $ \hw hh -> V2 (-hw) hh+  topRightCorner = runDisplaceCenter $ \hw hh -> V2   hw  hh++instance (Real u, Floating u) => BottomCornerAnchor (Rectangle u) where+  bottomLeftCorner  = runDisplaceCenter $ \hw hh -> V2 (-hw) (-hh)+  bottomRightCorner = runDisplaceCenter $ \hw hh -> V2   hw  (-hh)++instance (Real u, Floating u) => SideMidpointAnchor (Rectangle u) where+  sideMidpoint n a = step (n `mod` 4) +    where+      step 1 = north a+      step 2 = west a+      step 3 = south a+      step _ = east a++ instance (Real u, Floating u) => CardinalAnchor (Rectangle u) where-  north = runRectangle $ \_  hh -> projectPoint $ P2 0 hh-  south = runRectangle $ \_  hh -> projectPoint $ P2 0 (-hh)-  east  = runRectangle $ \hw _  -> projectPoint $ P2 hw 0-  west  = runRectangle $ \hw _  -> projectPoint $ P2 (-hw) 0+  north = runDisplaceCenter $ \_  hh -> V2 0 hh+  south = runDisplaceCenter $ \_  hh -> V2 0 (-hh)+  east  = runDisplaceCenter $ \hw _  -> V2 hw 0+  west  = runDisplaceCenter $ \hw _  -> V2 (-hw) 0  instance (Real u, Floating u) => CardinalAnchor2 (Rectangle u) where-  northeast = runRectangle $ \hw hh -> projectPoint $ P2 hw hh-  southeast = runRectangle $ \hw hh -> projectPoint $ P2 hw (-hh)-  southwest = runRectangle $ \hw hh -> projectPoint $ P2 (-hw) (-hh)-  northwest = runRectangle $ \hw hh -> projectPoint $ P2 (-hw) hh+  northeast = radialAnchor (0.25*pi)+  southeast = radialAnchor (1.75*pi)+  southwest = radialAnchor (1.25*pi)+  northwest = radialAnchor (0.75*pi)   instance (Real u, Floating u) => RadialAnchor (Rectangle u) where-  radialAnchor theta = runRectangle $ \hw hh -> -    projectPoint $ rectangleIntersect hw hh theta+  radialAnchor theta = runDisplaceCenter $ \hw hh -> +                          rectRadialVector hw hh theta --- Note - the answer needs projecting with the CTM...----rectangleIntersect :: (Real u, Floating u) -                   => u -> u -> Radian -> Point2 u-rectangleIntersect hw hh theta = -    maybe zeroPt id $ findIntersect zeroPt theta $ rectangleLines zeroPt hw hh   +--------------------------------------------------------------------------------+-- Construction + -- | 'rectangle'  : @ width * height -> shape @ -- rectangle :: (Real u, Floating u, FromPtSize u) -          => u -> u -> LocShape u (Rectangle u)+          => u -> u -> Shape u (Rectangle u) rectangle w h = -    intoLocShape (mkRectangle (0.5*w) (0.5*h))-                 (mkRectPath  (0.5*w) (0.5*h))+    makeShape (mkRectangle (0.5*w) (0.5*h))+              (mkRectPath  (0.5*w) (0.5*h))  -mkRectangle :: Num u => u -> u -> LocCF u (Rectangle u)-mkRectangle hw hh = promoteR1 $ \ctr -> -    pure $ Rectangle { rect_ctm    = makeShapeCTM ctr+mkRectangle :: Num u => u -> u -> LocThetaCF u (Rectangle u)+mkRectangle hw hh = promoteR2 $ \ctr theta -> +    pure $ Rectangle { rect_ctm    = makeShapeCTM ctr theta                      , rect_hw     = hw                      , rect_hh     = hh                      }   mkRectPath :: (Real u, Floating u, FromPtSize u) -           => u -> u -> LocCF u (Path u)-mkRectPath hw hh = promoteR1 $ \ctr -> +           => u -> u -> LocThetaCF u (Path u)+mkRectPath hw hh = promoteR2 $ \ctr theta ->      let btm_left = displace (-hw) (-hh) ctr-    in roundCornerShapePath $ rectangleCoordPath (2*hw) (2*hh) btm_left+    in roundCornerShapePath $ map (rotateAbout theta ctr)+                            $ rectangleCoordPath (2*hw) (2*hh) btm_left       
+ src/Wumpus/Drawing/Shapes/Semicircle.hs view
@@ -0,0 +1,235 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.Semicircle+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Semicircle. +-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.Semicircle+  ( ++    Semicircle+  , DSemicircle+  , semicircle++  ) where++import Wumpus.Drawing.Paths+import Wumpus.Drawing.Shapes.Base++import Wumpus.Basic.Geometry.Base               -- package: wumpus-basic+import Wumpus.Basic.Geometry.Intersection+import Wumpus.Basic.Kernel++import Wumpus.Core                              -- package: wumpus-core++import Data.AffineSpace                         -- package: vector-space+++import Control.Applicative++++--------------------------------------------------------------------------------+-- Datatype++data Semicircle u = Semicircle +      { sc_ctm          :: ShapeCTM u+      , sc_radius       :: !u +      , sc_syn_props    :: SyntheticProps u+      }++++-- | rect_width is the width of the (greater) enclosing rectangle.+data SyntheticProps u = SyntheticProps+      { sc_ctr_minor  :: u+      , sc_ctr_major  :: u+      }+  +type DSemicircle = Semicircle Double++type instance DUnit (Semicircle u) = u+++--------------------------------------------------------------------------------+-- Affine trans++mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Semicircle u -> Semicircle u+mapCTM f = (\s i -> s { sc_ctm = f i }) <*> sc_ctm++instance Num u => Scale (Semicircle u) where+  scale sx sy = mapCTM (scale sx sy)+++instance Rotate (Semicircle u) where+  rotate ang = mapCTM (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (Semicircle u) where+  rotateAbout ang pt = mapCTM (rotateAbout ang pt)+++instance Num u => Translate (Semicircle u) where+  translate dx dy = mapCTM (translate dx dy)+++--------------------------------------------------------------------------------+-- Anchors++-- | 'runDisplaceCenter' : @ ( radius+--                           * height_minor +--                           * height_major -> Vec ) * semicircle -> Point @+--+runDisplaceCenter :: (Real u, Floating u) +                  => (u -> u -> u -> Vec2 u) -> Semicircle u -> Point2 u+runDisplaceCenter fn (Semicircle { sc_ctm       = ctm+                                 , sc_radius    = radius+                                 , sc_syn_props = syn    }) = +    displaceCenter (fn radius (sc_ctr_minor syn) (sc_ctr_major syn)) ctm+++instance (Real u, Floating u) => CenterAnchor (Semicircle u) where+  center = runDisplaceCenter $ \_ _ _ -> V2 0 0++instance (Real u, Floating u) => ApexAnchor (Semicircle u) where+  apex = runDisplaceCenter $ \_ _    cmaj -> V2 0  cmaj++instance (Real u, Floating u) => BottomCornerAnchor (Semicircle u) where+  bottomLeftCorner  = runDisplaceCenter $ \r hminor _  -> V2 (-r) (-hminor)+  bottomRightCorner = runDisplaceCenter $ \r hminor _  -> V2  r   (-hminor)++instance (Real u, Floating u) => CardinalAnchor (Semicircle u) where+  north = apex+  south = runDisplaceCenter $ \_ cmin _    -> V2 0  (-cmin)+  east  = runDisplaceCenter $ \r cmin _    -> let x = pyth r cmin in V2 x 0+  west  = runDisplaceCenter $ \r cmin _    -> let x = pyth r cmin in V2 (-x) 0++-- | Use Pythagoras formula for working out the /east/ and /west/+-- distances. A right-triangle is formed below the centroid, +-- radius is the hypotenuese, hminor is the other side.+--+pyth :: Floating u => u -> u -> u+pyth hyp s1 = sqrt $ pow2 hyp - pow2 s1+  where+    pow2 = (^ (2::Int))+++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor2 (Semicircle u) where+  northeast = radialAnchor (0.25*pi)+  southeast = radialAnchor (1.75*pi)+  southwest = radialAnchor (1.25*pi)+  northwest = radialAnchor (0.75*pi)+++++instance (Real u, Floating u, FromPtSize u) => RadialAnchor (Semicircle u) where+  radialAnchor theta = runDisplaceCenter (scRadialVec theta)+++scRadialVec :: (Real u, Floating u, Ord u, FromPtSize u)+            => Radian -> u -> u -> u -> Vec2 u+scRadialVec theta radius hminor _ = go theta+  where+    (lang,rang)                     = baselineRange radius hminor+    (bctr, br, _, bl)               = constructionPoints radius hminor+    plane                           = makePlane zeroPt theta+    base_line                       = LineSegment bl br+    left_curve                      = mkCurve radius half_pi bctr+    right_curve                     = mkCurve radius 0 bctr+    post                            = maybe (V2 0 0) (\(P2 x y) -> V2 x y)+    go a | lang <= a && a <= rang   = post $ interLinesegLine base_line plane +         | half_pi <= a && a < lang = post $ interCurveLine left_curve plane+         | otherwise                = post $ interCurveLine right_curve plane+++mkCurve :: Floating u => u -> Radian -> Point2 u -> BezierCurve u+mkCurve radius theta ctr = BezierCurve p0 p1 p2 p3+  where+    (BezierCurve p0 p1 p2 p3) = bezierMinorArc half_pi radius theta ctr++++-- | 'constructionPoints' : @ radius * hminor -> +--     (base_ctr, base_right, apex, base_left) @+--+-- Assumes centroid is (0,0).+--+constructionPoints :: Num u +                   => u -> u -> (Point2 u, Point2 u, Point2 u, Point2 u)+constructionPoints radius hminor = (bctr, br, apx, bl)+  where+    bctr  = P2 0 (-hminor)+    br    = bctr .+^ hvec radius+    apx   = bctr .+^ vvec radius+    bl    = bctr .-^ hvec radius+++++-- | 'baselineRange' : @ radius * hminor -> (left_base_ang, right_base_ang) @+--+-- Find the angle range where a ray from the centroid will cross+-- the baseline rather than cut the curve.+--+baselineRange :: (Real u, Floating u) => u -> u -> (Radian, Radian)+baselineRange radius hminor = (lang, rang)+  where+    ang   = toRadian $ atan (radius / hminor)+    lang  = (1.5*pi) - ang+    rang  = (1.5*pi) + ang++--------------------------------------------------------------------------------+-- Construction++-- | 'semicircle'  : @ radius -> Shape @+--+semicircle :: (Real u, Floating u, FromPtSize u) +           => u -> Shape u (Semicircle u)+semicircle radius = +    let props = synthesizeProps radius+    in makeShape (mkSemicircle radius props) +                 (mkSemicirclePath radius (sc_ctr_minor props))+          ++synthesizeProps :: Floating u => u -> SyntheticProps u+synthesizeProps radius = +    SyntheticProps { sc_ctr_minor  = cminor+                   , sc_ctr_major  = cmajor+                   }+  where+    cminor = (4 * radius) / (3 * pi)+    cmajor = radius - cminor+++mkSemicircle :: Num u => u -> SyntheticProps u -> LocThetaCF u (Semicircle u)+mkSemicircle radius props = promoteR2 $ \ctr theta -> +    pure $ Semicircle { sc_ctm = makeShapeCTM ctr theta+                      , sc_radius = radius+                      , sc_syn_props = props +                      }++++-- TODO - need to check other shapes to see if the are deriving +-- the center properly...+--+mkSemicirclePath :: (Real u, Floating u, FromPtSize u) +                 => u -> u -> LocThetaCF u (Path u)+mkSemicirclePath radius cminor = promoteR2 $ \pt theta ->+    let ctr = displacePerpendicular (-cminor) theta pt+    in pure $ traceCurvePoints $ bezierArcPoints pi radius theta ctr +
+ src/Wumpus/Drawing/Shapes/Semiellipse.hs view
@@ -0,0 +1,265 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.Semiellipse+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Semiellipse.+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.Semiellipse+  ( ++    Semiellipse+  , DSemiellipse+  , semiellipse++  ) where++import Wumpus.Drawing.Paths+import Wumpus.Drawing.Shapes.Base++import Wumpus.Basic.Geometry.Base               -- package: wumpus-basic+import Wumpus.Basic.Geometry.Intersection+import Wumpus.Basic.Kernel++import Wumpus.Core                              -- package: wumpus-core++import Data.AffineSpace                         -- package: vector-space++import Control.Applicative++++--------------------------------------------------------------------------------+-- Datatype++data Semiellipse u = Semiellipse +      { se_ctm          :: ShapeCTM u+      , se_rx           :: !u +      , se_ry           :: !u+      , se_syn_props    :: SyntheticProps u+      }++++-- | rect_width is the width of the (greater) enclosing rectangle.+data SyntheticProps u = SyntheticProps+      { se_ry_minor  :: u+      , se_ry_major  :: u+      }+  +type DSemiellipse = Semiellipse Double++type instance DUnit (Semiellipse u) = u+++--------------------------------------------------------------------------------+-- Affine trans++mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Semiellipse u -> Semiellipse u+mapCTM f = (\s i -> s { se_ctm = f i }) <*> se_ctm++instance Num u => Scale (Semiellipse u) where+  scale sx sy = mapCTM (scale sx sy)+++instance Rotate (Semiellipse u) where+  rotate ang = mapCTM (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (Semiellipse u) where+  rotateAbout ang pt = mapCTM (rotateAbout ang pt)+++instance Num u => Translate (Semiellipse u) where+  translate dx dy = mapCTM (translate dx dy)+++--------------------------------------------------------------------------------+-- Anchors+++-- | 'runDisplaceCenter' : @ ( rx+--                           * ry +--                           * ry_minor +--                           * ry_major -> Vec ) * semiellipse -> Point @+--+runDisplaceCenter :: (Real u, Floating u) +                  => (u -> u -> u -> u -> Vec2 u) -> Semiellipse u -> Point2 u+runDisplaceCenter fn (Semiellipse { se_ctm       = ctm+                                  , se_rx        = rx+                                  , se_ry        = ry+                                  , se_syn_props = syn    }) = +    displaceCenter (fn rx ry (se_ry_minor syn) (se_ry_major syn)) ctm+++++instance (Real u, Floating u) => CenterAnchor (Semiellipse u) where+  center = runDisplaceCenter $ \_ _ _ _ -> V2 0 0++instance (Real u, Floating u, FromPtSize u) => +    ApexAnchor (Semiellipse u) where+  apex = runDisplaceCenter $ \_ _ _ ry_major -> V2 0 ry_major++instance (Real u, Floating u) => BottomCornerAnchor (Semiellipse u) where+  bottomLeftCorner  = runDisplaceCenter $ \rx _ ry_minor _  -> V2 (-rx) (-ry_minor)+  bottomRightCorner = runDisplaceCenter $ \rx _ ry_minor _  -> V2  rx   (-ry_minor)+++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor (Semiellipse u) where+  north = apex+  south = runDisplaceCenter $ \_ _ ry_minor _ -> V2 0 (-ry_minor)+  east  = radialAnchor 0+  west  = radialAnchor pi++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor2 (Semiellipse u) where+  northeast = radialAnchor (0.25*pi)+  southeast = radialAnchor (1.75*pi)+  southwest = radialAnchor (1.25*pi)+  northwest = radialAnchor (0.75*pi)++++instance (Real u, Floating u, FromPtSize u) => RadialAnchor (Semiellipse u) where+  radialAnchor theta = runDisplaceCenter (seRadialVec theta)+++seRadialVec :: (Real u, Floating u, Ord u, FromPtSize u)+            => Radian -> u -> u -> u -> u -> Vec2 u+seRadialVec theta rx ry hminor _ = go theta+  where+    (lang,rang)                     = baselineRange rx hminor+    (bctr, br, _, bl)               = constructionPoints rx ry hminor+    plane                           = makePlane zeroPt theta+    base_line                       = LineSegment bl br+    (right_curve,left_curve)        = bezierSemiellipse rx ry bctr+    post                            = maybe (V2 0 0) (\(P2 x y) -> V2 x y)+    go a | lang <= a && a <= rang   = post $ interLinesegLine base_line plane +         | half_pi <= a && a < lang = post $ interCurveLine left_curve plane+         | otherwise                = post $ interCurveLine right_curve plane++++-- | 'constructionPoints' : @ rx * ry * hminor -> +--     (base_ctr, base_right, apex, base_left) @+--+-- Assumes centroid is (0,0).+--+constructionPoints :: Num u +                   => u -> u -> u -> (Point2 u, Point2 u, Point2 u, Point2 u)+constructionPoints rx ry hminor = (bctr, br, apx, bl)+  where+    bctr  = P2 0 (-hminor)+    br    = bctr .+^ hvec rx+    apx   = bctr .+^ vvec ry+    bl    = bctr .+^ hvec (-rx)+++++-- | 'baselineRange' : @ radius * hminor -> (left_base_ang, right_base_ang) @+--+-- Find the angle range where a ray from the centroid will cross+-- the baseline rather than cut the curve.+--+baselineRange :: (Real u, Floating u) => u -> u -> (Radian, Radian)+baselineRange rx hminor = (lang, rang)+  where+    ang   = toRadian $ atan (rx / hminor)+    lang  = (1.5*pi) - ang+    rang  = (1.5*pi) + ang++++--------------------------------------------------------------------------------+-- Construction+++-- | 'semiellipse'  : @ x_radius * y_radius -> Shape @+--+semiellipse :: (Real u, Floating u, FromPtSize u) +            => u -> u -> Shape u (Semiellipse u)+semiellipse rx ry = +    let props = synthesizeProps ry+    in makeShape (mkSemiellipse rx ry props) +                 (mkSemiellipsePath rx ry (se_ry_minor props))+          +++synthesizeProps :: Floating u => u -> SyntheticProps u+synthesizeProps ry = +    SyntheticProps { se_ry_minor  = ry_minor+                   , se_ry_major  = ry_major+                   }+  where+    ry_minor = (4 * ry) / (3 * pi)+    ry_major = ry - ry_minor+++mkSemiellipse :: Num u +              => u -> u -> SyntheticProps u -> LocThetaCF u (Semiellipse u)+mkSemiellipse rx ry props = promoteR2 $ \ctr theta -> +    pure $ Semiellipse { se_ctm = makeShapeCTM ctr theta+                       , se_rx = rx+                       , se_ry = ry+                       , se_syn_props = props +                       }+++mkSemiellipsePath :: (Real u, Floating u, FromPtSize u) +                  => u -> u -> u -> LocThetaCF u (Path u)+mkSemiellipsePath rx ry cminor = promoteR2 $ \pt theta ->+    let ctr = displacePerpendicular (-cminor) theta pt+    in pure $ traceCurvePoints $ map (rotateAbout theta ctr)+                               $ bezierSemiellipsePoints rx ry ctr+++bezierSemiellipsePoints :: Floating u+                        => u -> u -> Point2 u -> [Point2 u]+bezierSemiellipsePoints rx ry pt = [ p0, c1,c2,p3, c4,c5,p6 ]+  where +    (BezierCurve p0 c1 c2 p3, BezierCurve _ c4 c5 p6) = bezierSemiellipse rx ry pt+++-- For Geometry?++-- | Generate the bezier arcs for quadrants I and II. +--+-- Drawing is expected to proceed CCW.+-- +-- Note - Point is the (full) ellipse center.+--+bezierSemiellipse :: Floating u+                  => u -> u -> Point2 u -> (BezierCurve u, BezierCurve u)+bezierSemiellipse rx ry (P2 x y) = +    (BezierCurve p00 c01 c02 p03, BezierCurve p03 c04 c05 p06)+  where+    lrx = rx * kappa+    lry = ry * kappa+    p00 = P2 (x + rx) y+    c01 = p00 .+^ vvec lry+    c02 = p03 .+^ hvec lrx++    p03 = P2 x (y + ry) +    c04 = p03 .+^ hvec (-lrx)+    c05 = p06 .+^ vvec lry++    p06 = P2 (x - rx) y++++kappa :: Floating u => u+kappa = 4 * ((sqrt 2 - 1) / 3)
+ src/Wumpus/Drawing/Shapes/Trapezium.hs view
@@ -0,0 +1,281 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.Trapezium+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Trapezium.+--+-- Note cardinal anchors correspond directly to the compass +-- positions.+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.Trapezium+  ( ++    Trapezium+  , DTrapezium+  , trapezium+  , ztrapezium+++  ) where++import Wumpus.Drawing.Paths+import Wumpus.Drawing.Shapes.Base++import Wumpus.Basic.Geometry.Intersection       -- package: wumpus-basic+import Wumpus.Basic.Geometry.Paths+import Wumpus.Basic.Kernel++import Wumpus.Core                              -- package: wumpus-core+++import Data.VectorSpace                         -- package: vector-space++import Control.Applicative+++++--------------------------------------------------------------------------------+-- Trapezium++-- | A trapezium.+--+data Trapezium u = Trapezium +      { tz_ctm          :: ShapeCTM u+      , tz_base_width   :: !u+      , tz_height       :: !u+      , tz_base_l_ang   :: Radian+      , tz_base_r_ang   :: Radian+      }+++type DTrapezium = Trapezium Double++type instance DUnit (Trapezium u) = u+++--------------------------------------------------------------------------------+-- Affine trans++mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Trapezium u -> Trapezium u+mapCTM f = (\s i -> s { tz_ctm = f i }) <*> tz_ctm++instance Num u => Scale (Trapezium u) where+  scale sx sy = mapCTM (scale sx sy)+++instance Rotate (Trapezium u) where+  rotate ang = mapCTM (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (Trapezium u) where+  rotateAbout ang pt = mapCTM (rotateAbout ang pt)+++instance Num u => Translate (Trapezium u) where+  translate dx dy = mapCTM (translate dx dy)+++--------------------------------------------------------------------------------+-- Anchors++-- | 'runDisplaceCenter' : @ ( half_base_width +--                           * half_height+--                           * left_base_ang +--                           * right_base_ang -> Vec ) * trapzium -> Point @+--+runDisplaceCenter :: (Real u, Floating u)+                  => (u -> u -> Radian -> Radian -> Vec2 u) +                  -> Trapezium u -> Point2 u+runDisplaceCenter fn (Trapezium { tz_ctm          = ctm+                                , tz_base_width   = bw+                                , tz_height       = h+                                , tz_base_l_ang   = lang+                                , tz_base_r_ang   = rang }) =+    displaceCenter (fn (0.5 * bw) (0.5 * h) lang rang) ctm++instance (Real u, Floating u) => CenterAnchor (Trapezium u) where+  center = runDisplaceCenter $ \_ _ _ _ -> V2 0 0++++instance (Real u, Floating u) => BottomCornerAnchor (Trapezium u) where+  bottomLeftCorner  = runDisplaceCenter $ \hbw hh _ _  -> V2 (-hbw) (-hh)+  bottomRightCorner = runDisplaceCenter $ \hbw hh _ _  -> V2  hbw   (-hh)+++instance (Real u, Floating u) => TopCornerAnchor (Trapezium u) where+  topLeftCorner  = runDisplaceCenter $ \hbw hh lang _  -> +                     let vbase = V2 (-hbw) (-hh)+                         vup   = leftSideVec (2*hh) lang +                     in vbase ^+^ vup+  topRightCorner = runDisplaceCenter $ \hbw hh _ rang  ->+                     let vbase = V2  hbw   (-hh)+                         vup   = rightSideVec (2*hh) rang+                     in vbase ^+^ vup+++instance (Real u, Floating u, FromPtSize u) => +    SideMidpointAnchor (Trapezium u) where+  sideMidpoint n a = step (n `mod` 4) +    where+      step 1 = north a+      step 2 = west a+      step 3 = south a+      step _ = east a++++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor (Trapezium u) where+  north = runDisplaceCenter $ \_ hh _ _ -> V2 0 hh+  south = runDisplaceCenter $ \_ hh _ _ -> V2 0 (-hh)+  east  = tzRadialAnchor 0+  west  = tzRadialAnchor pi+++instance (Real u, Floating u, FromPtSize u) => +    CardinalAnchor2 (Trapezium u) where+  northeast = tzRadialAnchor (0.25*pi)+  southeast = tzRadialAnchor (1.75*pi)+  southwest = tzRadialAnchor (1.25*pi)+  northwest = tzRadialAnchor (0.75*pi)++++instance (Real u, Floating u, FromPtSize u) => +    RadialAnchor (Trapezium u) where+  radialAnchor = tzRadialAnchor++-- TODO - update this to a quadrant function...+--+tzRadialAnchor :: (Real u, Floating u, FromPtSize u) +               => Radian -> Trapezium u -> Point2 u+tzRadialAnchor theta (Trapezium { tz_ctm        = ctm+                                , tz_base_width = bw+                                , tz_height     = h+                                , tz_base_l_ang = lang+                                , tz_base_r_ang = rang }) =+    post $ findIntersect zeroPt theta $ polygonLineSegments ps+  where +    ps   = tzPoints bw h lang rang+    post = \ans -> case ans of +                    Nothing       -> displaceCenter (V2 0 0) ctm+                    Just (P2 x y) -> displaceCenter (V2 x y) ctm+    +    +--------------------------------------------------------------------------------+-- Construction+++-- | 'trapezium'  : @ base_width * height * bottom_left_ang * +--     bottom_right_ang -> Shape @+--+--+trapezium :: (Real u, Floating u, FromPtSize u) +          => u -> u -> Radian -> Radian -> Shape u (Trapezium u)+trapezium bw h lang rang = +    makeShape (mkTrapezium bw h lang rang) (mkTrapeziumPath bw h lang rang)+++-- | 'ztrapezium'  : @ base_width * height -> Trapezium @+--+--+ztrapezium :: (Real u, Floating u, FromPtSize u) +           => u -> u -> Shape u (Trapezium u)+ztrapezium bw h = trapezium bw h ang ang+  where+    ang = d2r (60::Double)+++--------------------------------------------------------------------------------+++mkTrapezium :: (Real u, Fractional u) +            => u -> u -> Radian -> Radian -> LocThetaCF u (Trapezium u)+mkTrapezium bw h lang rang = promoteR2 $ \ctr theta -> +    pure $ Trapezium { tz_ctm           = makeShapeCTM ctr theta+                     , tz_base_width    = bw+                     , tz_height        = h+                     , tz_base_l_ang    = lang+                     , tz_base_r_ang    = rang+                     }+++mkTrapeziumPath :: (Real u, Floating u, FromPtSize u) +                => u -> u -> Radian -> Radian -> LocThetaCF u (Path u)+mkTrapeziumPath bw h lang rang = promoteR2 $ \ctr theta -> +    roundCornerShapePath $ map (rotateAbout theta ctr) +                         $ tzPath bw h lang rang ctr+++tzPath :: (Real u, Floating u) +       => u -> u -> Radian -> Radian -> LocCoordPath u+tzPath bw h lang rang (P2 x y) = [ bl, br, tr, tl ]+  where+    half_base = 0.5 * bw+    hh        = 0.5 * h+    br        = P2 (x + half_base ) (y - hh)+    bl        = P2 (x - half_base ) (y - hh)+    tr        = displaceVec (rightSideVec h rang) br+    tl        = displaceVec (leftSideVec h lang) bl+++tzPoints :: (Real u, Floating u) +               => u -> u -> Radian -> Radian -> [Point2 u]+tzPoints bw h lang rang = [ bl, br, tr, tl ]+  where+    half_base = 0.5 * bw+    hh        = 0.5 * h+    bl        = P2 (-half_base) (-hh)+    br        = P2 half_base    (-hh)+    tr        = displaceVec (rightSideVec h rang) br+    tl        = displaceVec (leftSideVec h lang) bl++++-- | Calculate the vector that produces the upper-left point given+-- the lower-left point.+--+-- Note - expects ang value 0 < ang < 180, though does not check...+-- +leftSideVec :: Floating u => u -> Radian -> Vec2 u+leftSideVec h lang | lang <  0.5*pi = less_ninety+                   | lang == 0.5*pi = vvec h+                   | otherwise      = grtr_ninety+  where+    less_ninety = let dist = h / (fromRadian $ sin lang) in avec lang dist+    grtr_ninety = let theta = lang - (0.5*pi) +                      dist  = h / (fromRadian $ cos theta) +                  in avec lang dist+++++-- | Calculate the vector that produces the upper-right point given+-- the lower-right point.+--+-- Note - expects ang value 0 < ang < 180, though does not check...+-- +rightSideVec :: Floating u => u -> Radian -> Vec2 u+rightSideVec h rang | rang <  0.5*pi = less_ninety+                    | rang == 0.5*pi = vvec h+                    | otherwise      = grtr_ninety+  where+    less_ninety = let dist  = h / (fromRadian $ sin rang) in avec (pi - rang) dist+    grtr_ninety = let theta = rang - (0.5*pi) +                      dist  = h / (fromRadian $ cos theta) +                  in avec (pi - rang) dist+
+ src/Wumpus/Drawing/Shapes/Triangle.hs view
@@ -0,0 +1,226 @@+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Shapes.Triangle+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Isosceles triangle.+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Shapes.Triangle+  ( ++    Triangle+  , DTriangle+  , triangle++  ) where++import Wumpus.Drawing.Paths+import Wumpus.Drawing.Shapes.Base++import Wumpus.Basic.Geometry.Base               -- package: wumpus-basic+import Wumpus.Basic.Geometry.Quadrant+import Wumpus.Basic.Geometry.Paths+import Wumpus.Basic.Kernel++import Wumpus.Core                              -- package: wumpus-core+++import Control.Applicative+++++-- Datatype++-- | An isosceles triangle, oriented /upwards/.+--+data Triangle u = Triangle +      { tri_ctm         :: ShapeCTM u+      , tri_height      :: !u+      , tri_base_width  :: !u+      , tri_syn_props   :: SyntheticProps u+      }+      +data SyntheticProps u = SyntheticProps+      { tri_hmajor      :: u           +      , tri_hminor      :: u+      , tri_base_ang    :: Radian+      , tri_apex_ang    :: Radian+      }+++type DTriangle = Triangle Double++type instance DUnit (Triangle u) = u+++--------------------------------------------------------------------------------+-- Affine trans++mapTriangleCTM :: (ShapeCTM u -> ShapeCTM u) +               -> Triangle u -> Triangle u+mapTriangleCTM f = (\s i -> s { tri_ctm = f i }) <*> tri_ctm++instance Num u => Scale (Triangle u) where+  scale sx sy = mapTriangleCTM (scale sx sy)+++instance Rotate (Triangle u) where+  rotate ang = mapTriangleCTM (rotate ang)+                  ++instance (Real u, Floating u) => RotateAbout (Triangle u) where+  rotateAbout ang pt = mapTriangleCTM (rotateAbout ang pt)+++instance Num u => Translate (Triangle u) where+  translate dx dy = mapTriangleCTM (translate dx dy)+++--------------------------------------------------------------------------------+-- Anchors++-- | 'runDisplaceCenter' : @ ( half_base_width +--                           * height_minor +--                           * height_major +--                           * base_ang -> Vec ) * traingle -> Point @+--+runDisplaceCenter :: (Real u, Floating u)+                  => (u -> u -> u -> Radian -> Vec2 u) -> Triangle u -> Point2 u+runDisplaceCenter fn (Triangle { tri_ctm        = ctm+                               , tri_base_width = bw+                               , tri_syn_props  = syn }) =  +    displaceCenter (fn (0.5*bw) hminor hmajor base_ang) ctm+  where+    hminor   = tri_hminor syn        +    hmajor   = tri_hmajor syn+    base_ang = tri_base_ang syn++++instance (Real u, Floating u) => CenterAnchor (Triangle u) where+  center = runDisplaceCenter $ \_ _ _ _ -> V2 0 0+++instance (Real u, Floating u) => ApexAnchor (Triangle u) where+  apex = runDisplaceCenter $ \_ _ hmaj _ -> V2 0 hmaj+++instance (Real u, Floating u) => BottomCornerAnchor (Triangle u) where+  bottomLeftCorner  = runDisplaceCenter $ \hbw hmin _ _  -> V2 (-hbw) (-hmin)+  bottomRightCorner = runDisplaceCenter $ \hbw hmin _ _  -> V2  hbw   (-hmin)+++-- east and west should be parallel to the centroid.+--++instance (Real u, Floating u) => CardinalAnchor (Triangle u) where+  north = runDisplaceCenter $ \_   _    hmaj _    -> V2 0 hmaj+  south = runDisplaceCenter $ \_   hmin _    _    -> V2 0 (-hmin)+  east  = runDisplaceCenter $ \hbw hmin _    ang  -> findEast hbw hmin ang+  west  = runDisplaceCenter $ \hbw hmin _    ang  -> findWest hbw hmin ang+++instance (Real u, Floating u) => SideMidpointAnchor (Triangle u) where+  sideMidpoint n a = step (n `mod` 3) +    where+      step 1 = midpoint (apex a) (bottomLeftCorner a)+      step 2 = midpoint (bottomLeftCorner a) (bottomRightCorner a)+      step _ = midpoint (bottomRightCorner a) (apex a)+++findEast :: Fractional u => u -> u -> Radian -> Vec2 u+findEast half_base_width hminor base_ang = V2 xdist 0+  where+    b1    = hminor / (fromRadian $ tan base_ang)+    xdist = half_base_width - b1++findWest :: Fractional u => u -> u -> Radian -> Vec2 u+findWest hbw hm ang = let (V2 xdist 0) = findEast hbw hm ang in V2 (-xdist) 0 ++++instance (Real u, Floating u) => CardinalAnchor2 (Triangle u) where+  northeast = radialAnchor (0.25*pi)+  southeast = radialAnchor (1.75*pi)+  southwest = radialAnchor (1.25*pi)+  northwest = radialAnchor (0.75*pi)++++instance (Real u, Floating u) => RadialAnchor (Triangle u) where+  radialAnchor theta = runDisplaceCenter $ \hbw hmin hmaj _ -> +                         triangleRadialVector hbw hmin hmaj theta+       +    +--------------------------------------------------------------------------------+-- Construction++-- | 'triangle'  : @ base_width * height -> Shape @+--+--+triangle :: (Real u, Floating u, FromPtSize u) +         => u -> u -> Shape u (Triangle u)+triangle bw h =+    let props  = synthesizeProps bw h+        hminor = tri_hminor props+        hmajor = tri_hmajor props+    in makeShape (mkTriangle bw h props) (mkTrianglePath bw hminor hmajor)++++++mkTriangle :: (Real u, Fractional u) +           => u -> u -> SyntheticProps u -> LocThetaCF u (Triangle u)+mkTriangle bw h props = promoteR2 $ \ctrd theta -> +    pure $ Triangle { tri_ctm        = makeShapeCTM ctrd theta+                    , tri_base_width = bw+                    , tri_height     = h +                    , tri_syn_props  = props+                    }+++synthesizeProps :: (Real u, Fractional u) => u -> u -> SyntheticProps u+synthesizeProps bw h = +    SyntheticProps { tri_hmajor      = hmajor+                   , tri_hminor      = hminor+                   , tri_base_ang    = base_ang+                   , tri_apex_ang    = apex_ang+                   }+  where+    half_base   = 0.5 * bw +    hminor      = h / 3+    hmajor      = 2 * hminor +    base_ang    = atan $ toRadian (h / half_base)+    apex_ang    = 2 * ((pi/4) - base_ang)++++mkTrianglePath :: (Real u, Floating u, FromPtSize u) +               => u -> u -> u -> LocThetaCF u (Path u)+mkTrianglePath bw hminor hmajor = promoteR2 $ \ctr theta -> +    roundCornerShapePath $ map (rotateAbout theta ctr) +                         $ trianglePath bw hminor hmajor ctr+++trianglePath :: (Real u, Floating u) +             => u -> u -> u -> LocCoordPath u+trianglePath bw hminor hmajor (P2 x y) = [br, apx, bl]+  where+    half_base = 0.5 * bw+    br        = P2 (x + half_base ) (y - hminor)+    apx       = P2 x (y + hmajor)+    bl        = P2 (x - half_base ) (y - hminor)+
+ src/Wumpus/Drawing/Text/Base.hs view
@@ -0,0 +1,166 @@+{-# LANGUAGE TypeFamilies               #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Text.Base+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  stephen.tetley@gmail.com+-- Stability   :  unstable+-- Portability :  GHC+--+-- Helpers for working with measured / advance text.+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Text.Base+  ( ++    advtext+  , textVector+  , charVector++  , multilineHeight+  , textObjectPos+  , borderedTextObjectPos++  , centerToBaseline+  , centerSpinePoints++  ) where++import Wumpus.Drawing.Chains++import Wumpus.Basic.Kernel                      -- package: wumpus-basic++import Wumpus.Core                              -- package: wumpus-core+import Wumpus.Core.Text.GlyphIndices++import Data.VectorSpace                         -- package: vector-space++import Control.Applicative+import Data.Char+import qualified Data.Map               as Map+import Data.Maybe +++-- | Single line text, returning its advance vector.+--+advtext :: FromPtSize u => EscapedText -> AdvGraphic u+advtext esc = lift0R1 (textVector esc) >>= \v -> replaceAns v $ escapedline esc+++-- kernchar versions to do...+++textVector :: FromPtSize u => EscapedText -> DrawingInfo (AdvanceVec u)+textVector esc = +    cwLookupTable >>= \table -> +       let cs = destrEscapedText id esc +       in return $ foldr (\c v -> v ^+^ (charWidth table c)) (vec 0 0) cs+     +charVector :: FromPtSize u => EscapedChar -> DrawingInfo (AdvanceVec u)+charVector ch = cwLookupTable >>= \table -> return $ charWidth table ch+   ++-- | This is outside the Drawing context as we don\'t want to get+-- the @cwLookupTable@ for every char.+--+charWidth :: FromPtSize u +          => CharWidthTable u -> EscapedChar -> AdvanceVec u+charWidth fn (CharLiteral c) = fn $ ord c+charWidth fn (CharEscInt i)  = fn i+charWidth fn (CharEscName s) = fn ix+  where+    ix = fromMaybe (-1) $ Map.lookup s ps_glyph_indices+++--------------------------------------------------------------------------------+-- Measurement and start points for multiline text+++-- | Height of multiline text is cap_height to descender for the +-- first line, then baseline-to-baseline span for the remaining+-- lines.+--+multilineHeight :: (Real u, Floating u, FromPtSize u) +                   => Int -> DrawingInfo u+multilineHeight line_count +    | line_count < 1  = return 0+    | line_count == 1 = glyphVerticalSpan+    | otherwise       = fn <$> glyphVerticalSpan <*> baselineSpacing+  where+    fn h1 bspan = let rest_spans = bspan * fromIntegral (line_count - 1)+                  in h1 + rest_spans++++-- | Height of multiline text is cap_height to descender for the +-- first line, then baseline-to-baseline span for the remaining+-- lines.+-- +-- The answer is in centerform, i.e.:+--+-- > ObjectPos  half_width  half_width  half_height  half_height +--+textObjectPos :: (Real u, Floating u, FromPtSize u) +                   => Int -> u -> DrawingInfo (ObjectPos u)+textObjectPos line_count w =+    fmap (0.5*) (multilineHeight line_count) >>= \hh ->+    let hw    = 0.5 * w+    in return $ ObjectPos hw hw hh hh +++-- | Variant of 'textObjectPos' where the calculation includes+-- margins around all four sides of the enclosing rectangle.+--+-- Margin sizes are taken from the 'text_margin' field in the +-- 'DrawingContext'.+--+borderedTextObjectPos :: (Real u, Floating u, FromPtSize u) +                      => Int -> u -> DrawingInfo (ObjectPos u)+borderedTextObjectPos line_count w =+    multilineHeight line_count >>= \h ->+    getTextMargin >>= \(xsep,ysep) -> +    let hw    = (2 * xsep) + (0.5 * w)+        hh    = (2 * ysep) + (0.5 * h)+    in return $ ObjectPos hw hw hh hh ++++-- | Calculate the distance from the center of a one-line textbox +-- to the baseline. Note the height of a textbox is @vspan@ which +-- is cap_height + descender+--+centerToBaseline :: (Fractional u, FromPtSize u) => DrawingInfo u+centerToBaseline = +    (\ch vspan -> ch - 0.5 * vspan) <$> glyphCapHeight <*> glyphVerticalSpan++-- | All drawing is done on a spine that plots points from the +-- first line of text. The spine is calculated from its center and+-- has to account for the inclination.+--+centerSpinePoints :: Floating u +                  => Int -> Radian -> LocChain u+centerSpinePoints n theta+    | n <= 1    = promoteR1 $ \ctr -> return [ctr]+    | otherwise = promoteR1 $ \ctr -> +                    baselineSpacing >>= \h1 -> +                    let dist_top = h1 * centerCount n+                        top      = thetaNorthwards dist_top theta ctr    +                    in return (take n $ iterate (thetaSouthwards h1 theta) top)+++-- | Count the steps from the center to an end:+--+-- >+-- > 1 = 0     .+-- > 2 = 0.5   .__.+-- > 3 = 1     .__.__.+-- > 4 = 1.5   .__.__.__.+-- >+--+centerCount :: Fractional u => Int -> u+centerCount i = (fromIntegral i) / 2 - 0.5
+ src/Wumpus/Drawing/Text/CatText.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE TypeFamilies               #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Drawing.Text.Text+-- Copyright   :  (c) Stephen Tetley 2011+-- License     :  BSD3+--+-- Maintainer  :  stephen.tetley@gmail.com+-- Stability   :  unstable+-- Portability :  GHC+--+-- Left-to-right text.+-- +--------------------------------------------------------------------------------++module Wumpus.Drawing.Text.CatText+  ( +   +    CatText+  , leftAlign+  , centerAlign+  , rightAlign++  , blank+  , space+  , string+  , (<>)+  , (<+>) ++  , fontColour++  ) where++import Wumpus.Drawing.Chains+import Wumpus.Drawing.Text.Base++import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Basic.Utils.JoinList ( JoinList, ViewL(..), viewl )+import qualified Wumpus.Basic.Utils.JoinList as JL++import Wumpus.Core                              -- package: wumpus-core++import Data.Char ( ord )++-- Need to know line width (horizontal) and line count (vertical) +-- to render...+--+-- Can obviously access line count if we avoid avoid operators +-- for vertical composition operator and delegate it to rendering+-- instead:+--+-- > rightAlign :: [CatText u] -> PosImage u (BoundingBox u)+--++-- A CatPrim returns a drawing function (AdvGraphic) to be used+-- drawing final rendering.+--+type CatPrim u = CF (u, AdvGraphic u)++newtype CatText u = CatText { getCatText :: JoinList (CatPrim u) }++++-- | 'HMove' : @ half_max_width * line_width -> Horizontal_Displacement @+--+type HMove u = u -> u -> u++leftAMove :: Num u => HMove u+leftAMove half_max _ = negate half_max+ +centerAMove :: Fractional u => HMove u+centerAMove _ elt_w = negate $ 0.5 * elt_w++rightAMove :: Num u => HMove u+rightAMove half_max elt_w = half_max - elt_w++++leftAlign :: (Real u, FromPtSize u, Floating u) +          => [CatText u] -> PosImage u (BoundingBox u)+leftAlign = drawMulti leftAMove++centerAlign :: (Real u, FromPtSize u, Floating u) +            => [CatText u] -> PosImage u (BoundingBox u)+centerAlign = drawMulti centerAMove++rightAlign :: (Real u, FromPtSize u, Floating u) +           => [CatText u] -> PosImage u (BoundingBox u)+rightAlign = drawMulti rightAMove++++drawMulti :: (Real u, FromPtSize u, Floating u) +          => HMove u -> [CatText u] -> PosImage u (BoundingBox u)+drawMulti moveF xs = promoteR2 $ \start rpos -> +    evalAllLines xs                     >>= \all_lines -> +    centerToBaseline                    >>= \down -> +    borderedTextObjectPos line_count (fst all_lines) >>= \opos ->+    let chn   = centerSpinePoints line_count 0 +        gs    = positionHLines moveF down all_lines +        gf    = unchainZip emptyLocGraphic gs chn+        posG  = makePosImage opos gf+        bbox  = objectPosBounds start rpos opos+    in replaceAns bbox $ atStartPos posG start rpos     +  where+    line_count    = length xs++positionHLines :: Fractional u +               => HMove u -> u -> (u,[(u, AdvGraphic u)]) -> [LocGraphic u]+positionHLines mkH down (max_w,xs) = map fn xs+  where+    half_max       = 0.5 * max_w+    moveF w1       = let v = vec (mkH half_max w1) (-down) +                     in moveStart $ displaceVec v +    fn (elt_w, gf) = ignoreAns $ moveF elt_w $ gf+++evalAllLines :: (Num u, Ord u) +             => [CatText u] -> DrawingInfo (u, [(u, AdvGraphic u)])+evalAllLines = fmap post . mapM evalLine+  where+    post xs = let mx = foldr (\(a,_) x -> max a x) 0 xs in (mx,xs)+            +++++evalLine :: Num u => CatText u -> DrawingInfo (u, AdvGraphic u)+evalLine ct = case viewl $ getCatText ct of+    EmptyL -> return (0,  replaceAns (hvec 0) $ emptyLocGraphic)+    af :< rest -> af >>= \a -> go a (viewl rest)+  where+    go acc     EmptyL     = return acc+    go (dx,af) (mf :< ms) = let moveF = moveStart (displaceH dx)+                            in mf >>= \(u,gf) -> +                               go (dx+u, af `oplus` moveF gf) (viewl ms)++++++-- | Build a blank CatText with no output and a 0 width vector.+--+blank :: Num u => CatText u+blank = catOne $ return (0, replaceAns (hvec 0) $ emptyLocGraphic)++-- | Note - a space character is not draw in the output, instead +-- 'space' advances the width vector by the width of a space in +-- the current font.+--+space :: FromPtSize u => CatText u+space = catOne $ +   charVector (CharEscInt $ ord ' ') >>= \v -> +   return (advanceH v, replaceAns v $ emptyLocGraphic)++-- | Build a CatText from a string.+--+string :: FromPtSize u => String -> CatText u+string = catOne . stringPrim+++infixr 6 <>, <+>++-- | Concatenate two CatTexts separated with no spacing.+--+(<>) :: CatText u -> CatText u -> CatText u+a <> b = CatText $ JL.join (getCatText a) (getCatText b) +++-- | Concatenate two CatTexts separated with a space.+--+(<+>) :: FromPtSize u => CatText u -> CatText u -> CatText u+a <+> b = a <> space <> b ++++-- Note - @fill@ combinators cf. @wl-pprint@ (but left and right) +-- will be very useful.+--+-- Also PosImages can be inlined in text...+--++catOne :: CatPrim u -> CatText u+catOne = CatText . JL.one +++stringPrim :: FromPtSize u => String -> CatPrim u+stringPrim = escapedPrim . escapeString++escapedPrim :: FromPtSize u => EscapedText -> CatPrim u+escapedPrim esc = textVector esc >>= \v -> +                  return (vector_x v, replaceAns v $ escapedline esc)+++catMap :: (AdvGraphic u -> AdvGraphic u) -> CatText u -> CatText u+catMap f = CatText . fmap (fmap (\(u,ag) -> (u, f $ ag))) . getCatText++catlocal :: DrawingContextF -> CatText u -> CatText u+catlocal fn = catMap (localize fn)+++fontColour :: RGBi -> CatText u -> CatText u+fontColour rgb = catlocal (strokeColour rgb)++
src/Wumpus/Drawing/Text/LRText.hs view
@@ -4,385 +4,285 @@ -------------------------------------------------------------------------------- -- | -- Module      :  Wumpus.Drawing.Text.LRText--- Copyright   :  (c) Stephen Tetley 2010+-- Copyright   :  (c) Stephen Tetley 2011 -- License     :  BSD3 -- -- Maintainer  :  stephen.tetley@gmail.com -- Stability   :  unstable -- Portability :  GHC ----- Left-to-right measured text. The text uses glyph metrics so it --- can be positioned accurately.+-- Left-to-right measured text that supports radial inclination.+-- Caveat - rendering at any degree other than the horizontal may+-- not look good in PostScript or SVG. -- --- \*\* WARNING \*\* - the API for this module needs work. The --- current API is not satisfactory for drawing according to a --- start position (there are other reasonable start positions than --- the ones currently supported - adding them would explode the --- number of definitions).+-- Note - LRText does not use the 'text_margin' setting from the +-- 'DrawingContext'.+--+-- \*\* WARNING \*\* - the API for this module needs some polish.+-- --  --------------------------------------------------------------------------------  module Wumpus.Drawing.Text.LRText   (  -    baseCenterLine-  , baseLeftLine-  , baseRightLine--  , rbaseCenterLine-  , rbaseLeftLine-  , rbaseRightLine--  , ctrCenterLine-  , baseCenterEscChar+    singleLine+  , escSingleLine+  , rsingleLine+  , rescSingleLine    , multiAlignLeft   , multiAlignCenter   , multiAlignRight -  , rmultiAlignLeft-  , rmultiAlignCenter-  , rmultiAlignRight- +  , textAlignCenter+  , textAlignLeft+  , textAlignRight    ) where +import Wumpus.Drawing.Chains+import Wumpus.Drawing.Text.Base -import Wumpus.Basic.Kernel+import Wumpus.Basic.Kernel                      -- package: wumpus-basic  import Wumpus.Core                              -- package: wumpus-core-import Wumpus.Core.Text.GlyphIndices  import Data.AffineSpace                         -- package: vector-space import Data.VectorSpace -import Control.Applicative-import Data.Char-import qualified Data.Map               as Map-import Data.Maybe  ---- Note - BoundedLocThetaGraphic is probably an adequate type--- even though the same text will have a different bounding box--- if it is rotated (the sides of the BBox are always parallel to --- the x and y axes even if the text is not parrale to the --- x-axis). --- --- I cannot think of any compelling graphics that need a more --- accurate type. The execption is text cannot have exact anchors --- however this is a moot /if/ text is considered as a labelling --- of an existing rectangle (which may or may not have been --- rotated). --+-- Note - margins are not added to the text. This seems to be the +-- right thing to do in the case of rotated text, where the ortho+-- projection of the rectangle already can add spacing between +-- the RectPos and the actual text.+--  +------------------- --- One line of multiline text+-- | One line of multiline text ---data OnelineText u = OnelineText EscapedText (AdvanceVec u)-+data OnelineText u = OnelineText +        { text_content        :: EscapedText+        , oneline_adv         :: AdvanceVec u+        } --- | max_width * oneline_text -> LocThetaGraphic+-- Design note - using a LocThetaImage could be used instead, but+-- as the angle of inclination is interior to the final type the +-- it is used explicitly. ---type LocThetaDrawOneline u = u -> OnelineText u -> LocThetaGraphic u+type OnelineDrawF u = +    Radian -> AdvanceVec u -> OnelineText u -> LocImage u (BoundingBox u)  --- | max_width * oneline_text -> LocThetaGraphic----type BoundedLocThetaOneline u = u -> OnelineText u -> BoundedLocThetaGraphic u  --- | Draw one line of left-aligned text, knowing the max_width --- of all the lines of text.------ All left-aligned text is moved left by half the max_width.------ Note - implicit point is baseline-center, this is perhaps --- unintituitive given the functions name but it is an --- advantage for drawing multi-line text.--- -drawLeftAligned :: Floating u => LocThetaDrawOneline u-drawLeftAligned max_width (OnelineText esc _) = -    promoteR2 $ \baseline_ctr theta -> -       let mv = displaceParallel ((-0.5) * max_width) theta-       in apply2R2 (rescapedline esc) (mv baseline_ctr) theta-       +singleLine :: (Real u, Floating u, FromPtSize u) +           => String -> PosImage u (BoundingBox u)+singleLine ss = onelineDraw onelineACenter 0 (escapeString ss) +escSingleLine :: (Real u, Floating u, FromPtSize u) +              => EscapedText -> PosImage u (BoundingBox u)+escSingleLine = onelineDraw onelineACenter 0 --- | Draw one line of center-aligned text. Center aligned text is --- oblivious to the max_width of all the lines of text.------ Each line of center-aligned text is moved left by half its --- advance vector.------ Implicit point is baseline-center.----drawCenterAligned :: Floating u => LocThetaDrawOneline u-drawCenterAligned _ (OnelineText esc av) = -    promoteR2 $ \baseline_ctr theta -> -       let mv = displaceParallel (negate $ 0.5 * advanceH av) theta-       in apply2R2 (rescapedline esc) (mv baseline_ctr) theta-        --- | Draw one line of right-aligned text, knowing the max_width --- of all the lines of text.------ Each right-aligned text line is moved by the width component --- of the advance vector minus half the max width.------ Note - implicit point is baseline-center, this is perhaps --- unintituitive given the functions name but it is an --- advantage for drawing multi-line text.--- -drawRightAligned :: Floating u => LocThetaDrawOneline u-drawRightAligned max_width (OnelineText esc av) = -    promoteR2 $ \baseline_ctr theta -> -      let mv = displaceParallel ((0.5 * max_width) - advanceH av) theta-      in apply2R2 (rescapedline esc) (mv baseline_ctr) theta+rsingleLine :: (Real u, Floating u, FromPtSize u) +            => Radian -> String -> PosImage u (BoundingBox u)+rsingleLine theta ss = onelineDraw onelineACenter theta (escapeString ss) +rescSingleLine :: (Real u, Floating u, FromPtSize u) +               => Radian -> EscapedText -> PosImage u (BoundingBox u)+rescSingleLine = onelineDraw onelineACenter +multiAlignLeft :: (Real u, Floating u, FromPtSize u) +               => Radian -> String -> PosImage u (BoundingBox u)+multiAlignLeft theta ss = +   drawMultiline onelineALeft theta (map escapeString $ lines ss) +multiAlignCenter :: (Real u, Floating u, FromPtSize u) +               => Radian -> String -> PosImage u (BoundingBox u)+multiAlignCenter theta ss = +   drawMultiline onelineACenter theta (map escapeString $ lines ss) --- Impilict point is baseline-center.----onelineBBox :: (Real u, Floating u, FromPtSize u) -            => OnelineText u -> LocThetaDrawingInfo u (BoundingBox u)-onelineBBox (OnelineText _ av) = -    promoteR2 $ \baseline_ctr theta -> -      glyphHeightRange >>= \(ymin, ymax) ->-      getTextMargin    >>= \(xsep, ysep) -> -        let hw        = 0.5 * advanceH av -            btm_left  = baseline_ctr .+^ vec (-hw) ymin-            top_right = baseline_ctr .+^ vec hw    ymax-            bbox      = expandBB xsep ysep (BBox btm_left top_right)-        in pure $ centerOrthoBBox theta bbox-  where-    expandBB xsep ysep (BBox (P2 x0 y0) (P2 x1 y1)) = -        BBox (P2 (x0-xsep) (y0-ysep)) (P2 (x1+xsep) (y1+ysep))-    +multiAlignRight :: (Real u, Floating u, FromPtSize u) +               => Radian -> String -> PosImage u (BoundingBox u)+multiAlignRight theta ss = +   drawMultiline onelineARight theta (map escapeString $ lines ss)  +textAlignLeft :: (Real u, Floating u, FromPtSize u) +              => String -> LocImage u (BoundingBox u)+textAlignLeft ss = multiAlignLeft 0 ss `startPos` CENTER +textAlignCenter :: (Real u, Floating u, FromPtSize u) +               => String -> LocImage u (BoundingBox u)+textAlignCenter ss = multiAlignCenter 0 ss `startPos` CENTER  +textAlignRight :: (Real u, Floating u, FromPtSize u) +               => String -> LocImage u (BoundingBox u)+textAlignRight ss = multiAlignRight 0 ss `startPos` CENTER   --- This should have max_width as a param...----makeMoveableLine :: (Real u, Floating u, FromPtSize u) -                 => LocThetaDrawOneline u -                 -> BoundedLocThetaOneline u-makeMoveableLine drawF max_width oline =-      intoLocThetaImage (onelineBBox oline) (drawF max_width oline) -onelineAlg :: (Real u, Floating u, FromPtSize u) -           => DisplaceFun u -           -> LocThetaDrawOneline u -           -> EscapedText-           -> BoundedLocThetaGraphic u-onelineAlg ptMoveF drawF esc = -   promoteR2 $ \pt theta -> -     onelineEscText esc >>= \ans@(OnelineText _ av) ->-       let max_width = advanceH av-           move      = ptMoveF max_width ans theta -       in apply2R2 (makeMoveableLine drawF max_width ans) (move pt) theta +-- Note - inclination is not part of the ContextFunction... +drawMultiline :: (Real u, Floating u, FromPtSize u) +              => OnelineDrawF u -> Radian -> [EscapedText] +              -> PosImage u (BoundingBox u)+drawMultiline _     _     []  = lift1R2 emptyBoundedLocGraphic+drawMultiline drawF theta [x] = onelineDraw drawF theta x+drawMultiline drawF theta xs  = promoteR2 $ \start rpos ->+    linesToInterims xs >>= \(max_adv, ones) -> +    rotObjectPos theta line_count (advanceH max_adv) >>= \opos -> +    let chn   = centerSpinePoints line_count theta+        gs    = map (drawF theta max_adv) ones+        gf    = unchainZip emptyBoundedLocGraphic gs chn+        posG  = makePosImage opos gf+    in  atStartPos posG start rpos     +  where+    line_count = length xs   --- | Draw 1 line...------ Impilict point is baseline-left.--- -baseLeftLine :: (Real u, Floating u, FromPtSize u) -              => String -> BoundedLocGraphic u-baseLeftLine ss = rbaseLeftLine ss `rot` 0-+onelineDraw :: (Real u, Floating u, FromPtSize u) +            => OnelineDrawF u -> Radian -> EscapedText -> PosImage u (BoundingBox u)+onelineDraw drawF theta esc = promoteR2 $ \start rpos ->+    onelineEscText esc        >>= \otext -> +    rotObjectPos theta 1 (advanceH $ oneline_adv otext) >>= \opos  -> +    let max_adv = oneline_adv otext +        gf      = drawF theta max_adv otext+        posG    = makePosImage opos gf+    in  atStartPos posG start rpos   --- | Draw 1 line...------ Impilict point is baseline-center.+-- | LR text needs the objectPos under rotation. ---baseCenterLine :: (Real u, Floating u, FromPtSize u) -               => String -> BoundedLocGraphic u-baseCenterLine ss = rbaseCenterLine ss `rot` 0+rotObjectPos :: (Real u, Floating u, FromPtSize u) +             => Radian -> Int -> u -> DrawingInfo (ObjectPos u)+rotObjectPos theta line_count max_w =+    fmap (orthoObjectPos theta) $ textObjectPos line_count max_w    +     --- | Draw 1 line...------ Impilict point is baseline-right.+-- | Note - this returns the answer in center form, regardless+-- of whether the input was in center form.+-- +-- So it is probably not a general enough function for the +-- PosImage library. ---baseRightLine :: (Real u, Floating u, FromPtSize u) -              => String -> BoundedLocGraphic u-baseRightLine ss = rbaseRightLine ss `rot` 0+orthoObjectPos :: (Real u, Floating u) +               => Radian -> ObjectPos u -> ObjectPos u+orthoObjectPos theta (ObjectPos xmin xmaj ymin ymaj) = +    ObjectPos bbox_hw bbox_hw bbox_hh bbox_hh+  where+    input_hw  = 0.5 * (xmin + xmaj)+    input_hh  = 0.5 * (ymin + ymaj)+    bbox0     = BBox (P2 (-input_hw) (-input_hh)) (P2 input_hw input_hh)+    bbox1     = retraceBoundary (rotateAbout theta zeroPt) bbox0+    bbox_hw   = 0.5 * (boundaryWidth bbox1)+    bbox_hh   = 0.5 * (boundaryHeight bbox1)   -rbaseLeftLine :: (Real u, Floating u, FromPtSize u) -              => String -> BoundedLocThetaGraphic u-rbaseLeftLine ss = -    onelineAlg leftToCenter drawLeftAligned (escapeString ss)  -rbaseCenterLine :: (Real u, Floating u, FromPtSize u) -                => String -> BoundedLocThetaGraphic u-rbaseCenterLine ss = -    onelineAlg centerToCenter drawCenterAligned (escapeString ss)  -rbaseRightLine :: (Real u, Floating u, FromPtSize u) -              => String -> BoundedLocThetaGraphic u-rbaseRightLine ss = -    onelineAlg rightToCenter drawRightAligned (escapeString ss)----- Note - assumes the ymin of the font is 0 or less.+-- | Draw left-aligned text. Effictively this is: ---ctrCenterLine :: (Real u, Floating u, FromPtSize u) -              => String -> BoundedLocGraphic u-ctrCenterLine ss =-    glyphHeightRange >>= \(ymin, ymax) -> -      let hh = 0.5 * ymax - ymin in -        moveStartPoint (displaceV $ negate $ hh - abs ymin) $ baseCenterLine ss----baseCenterEscChar :: (Real u, Floating u, FromPtSize u) -                  => EscapedChar -> BoundedLocGraphic u-baseCenterEscChar esc = body `rot` 0+-- > Leftwards for the half the max vector+-- >+-- > Down to the baseline from the center.+--+onelineALeft :: (Real u, Floating u, FromPtSize u)  +             => OnelineDrawF u +onelineALeft theta max_adv otext = promoteR1 $ \ctr -> +    centerToBaseline >>= \down -> +    atRot (orthoBB max_adv) ctr theta >>= \bbox -> +    let pt = move down theta ctr +    in replaceAns bbox $ atRot (rescapedline $ text_content otext) pt theta   where-    body = onelineAlg centerToCenter drawCenterAligned (wrapEscChar esc)----+    vec1      = negateV $ 0.5 *^ max_adv+    move down = \ang -> thetaSouthwards down ang . displaceOrtho vec1 ang  --- | max_width * interim_text * theta -> (Point -> Point)+-- | Draw center-aligned text. Effictively this is: ---type DisplaceFun u = u -> OnelineText u -> Radian -> PointDisplace u--centerToCenter :: DisplaceFun u-centerToCenter _ _ _ = id--leftToCenter :: Floating u => DisplaceFun u-leftToCenter max_width _ theta =-    displaceParallel (0.5 * max_width) theta--rightToCenter :: Floating u => DisplaceFun u-rightToCenter max_width (OnelineText _ av) theta =-    displaceParallel ((0.5 * max_width) - advanceH av) theta-----multiAlignLeft :: (Floating u, Real u, Ord u, FromPtSize u)-               => String-               -> BoundedLocGraphic u-multiAlignLeft ss = rmultiAlignLeft ss `rot` 0---multiAlignCenter :: (Floating u, Real u, Ord u, FromPtSize u)-                 => String-                 -> BoundedLocGraphic u-multiAlignCenter ss = rmultiAlignCenter ss `rot` 0-----multiAlignRight :: (Floating u, Real u, Ord u, FromPtSize u)-                => String-                -> BoundedLocGraphic u-multiAlignRight ss = rmultiAlignRight ss `rot` 0---rmultiAlignLeft :: (Floating u, Real u, Ord u, FromPtSize u)-               => String-               -> BoundedLocThetaGraphic u-rmultiAlignLeft = multilineTEXT (makeMoveableLine drawLeftAligned)---rmultiAlignCenter :: (Floating u, Real u, Ord u, FromPtSize u)-                  => String-                  -> BoundedLocThetaGraphic u-rmultiAlignCenter = multilineTEXT (makeMoveableLine drawCenterAligned)---rmultiAlignRight :: (Floating u, Real u, Ord u, FromPtSize u)-                 => String-                 -> BoundedLocThetaGraphic u-rmultiAlignRight = multilineTEXT (makeMoveableLine drawRightAligned)----multilineTEXT :: (Floating u, Ord u, FromPtSize u)-              => BoundedLocThetaOneline u-              -> String-              -> BoundedLocThetaGraphic u-multilineTEXT _  [] = lift1R2 emptyBoundedLocGraphic-multilineTEXT mf ss = -    lift0R2 (linesToInterims ss) >>= \(max_av, itexts) -> -      centralPoints (length itexts) >>= \pts -> -        zipMultis (advanceH max_av) mf itexts pts---      --zipMultis :: (Ord u, FromPtSize u)-          => u-          -> BoundedLocThetaOneline u-          -> [OnelineText u] -> [Point2 u]-          -> BoundedLocThetaGraphic u-zipMultis _     _  []     _       = lift1R2 $ emptyBoundedLocGraphic-zipMultis _     _  _      []      = lift1R2 $ emptyBoundedLocGraphic-zipMultis max_w mf (a:as) (b:bs) = step a b as bs+-- > Leftwards for the half the width vector+-- >+-- > Down to the baseline from the center.+--+onelineACenter :: (Real u, Floating u, FromPtSize u)  +               => OnelineDrawF u+onelineACenter theta max_adv otext = promoteR1 $ \ctr -> +    centerToBaseline >>= \down -> +    atRot (orthoBB max_adv) ctr theta >>= \bbox ->  +    let pt = move down theta ctr +    in replaceAns bbox $ atRot (rescapedline $ text_content otext) pt theta   where-    mkGraphic itext pt        = promoteR2 $ \_ theta -> -                                  apply2R2 (mf max_w itext) pt theta-    step r s (r2:rs) (s2:ss)  = liftA2 oplus (mkGraphic r s) (step r2 s2 rs ss)-    step r s _       _        = mkGraphic r s--+    vec1      = negateV $ 0.5 *^ oneline_adv otext+    move down = \ang -> thetaSouthwards down ang . displaceOrtho vec1 ang  --- | @ana@ is an /anacrusis/ factor - if there are even points--- half the baseline_spacing is added to get the top point+-- | Draw right-aligned text. Effictively this is: ---centralPoints :: Floating u => Int -> LocThetaDrawingInfo u [Point2 u]-centralPoints n | n < 2     = promoteR2 $ \ctr _  -> return [ctr]-                | even n    = body (n `div` 2) (0.5*)-                | otherwise = body (n `div` 2) (0 *) +-- > Rightwards for the half the max vector+-- >+-- > Leftwards for the width vector+-- >+-- > Down to the baseline from the center.+--+onelineARight :: (Real u, Floating u, FromPtSize u)  +              => OnelineDrawF u+onelineARight theta max_adv otext = promoteR1 $ \ctr -> +    centerToBaseline >>= \down -> +    atRot (orthoBB max_adv) ctr theta >>= \bbox -> +    let pt = move down theta ctr +    in replaceAns bbox $ atRot (rescapedline $ text_content otext) pt theta   where-    body halfn ana  = promoteR2 $ \ctr theta -> -                        baselineSpacing >>= \h ->-                          let y0  = (h * fromIntegral halfn) + ana h-                              top = displacePerpendicular y0 theta ctr-                          in pure $ trailPoints n h theta top-        +    vec1      = (0.5 *^ max_adv) ^-^ oneline_adv otext+    move down = \ang -> thetaSouthwards down ang . displaceOrtho vec1 ang  -trailPoints :: Floating u => Int -> u -> Radian -> Point2 u -> [Point2 u]-trailPoints n height theta top = take n $ iterate fn top-  where-    fn pt = displacePerpendicular (-height) theta pt +-- Note - for multiline text, the bounding box (of one line) is +-- always the same size regardless of the alignment of the textlines.+--+orthoBB :: (Real u, Floating u, FromPtSize u) +        => AdvanceVec u -> LocThetaDrawingInfo u (BoundingBox u)+orthoBB (V2 w _) = promoteR2 $ \ctr theta -> +    glyphVerticalSpan >>= \h ->+    let bl  = ctr .-^ V2 (0.5 * w) (0.5 * h)+        bb1 = boundingBox bl (bl .+^ V2 w h)+        bb2 = retraceBoundary (rotateAbout theta ctr) bb1+    in return bb2  + --------------------------------------------------------------------------------  -- This isn't worth the complexity to get down to one traversal... +-- | Turn the input list of lines of 'EscapedText' into +-- 'OnelineText' and return the result list twinned with the +-- largest 'AdvanceVec'.+-- linesToInterims :: (FromPtSize u, Ord u) -                => String -> DrawingInfo (AdvanceVec u, [OnelineText u])-linesToInterims = fmap post . mapM (onelineEscText . escapeString) . lines+                => [EscapedText] -> DrawingInfo (AdvanceVec u, [OnelineText u])+linesToInterims = fmap post . mapM onelineEscText   where     post xs                    = let vmax = foldr fn (hvec 0) xs in (vmax,xs)     fn (OnelineText _ av) vmax = avMaxWidth av vmax +++ avMaxWidth :: Ord u => AdvanceVec u -> AdvanceVec u -> AdvanceVec u avMaxWidth a@(V2 w1 _) b@(V2 w2 _) = if w2 > w1 then b else a @@ -390,20 +290,3 @@ onelineEscText esc = fmap (OnelineText esc) $ textVector esc  --textVector :: FromPtSize u => EscapedText -> DrawingInfo (AdvanceVec u)-textVector esc = -    cwLookupTable >>= \table -> -       let cs = destrEscapedText id esc -       in pure $ foldr (\c v -> v ^+^ (charWidth table c)) (vec 0 0) cs-     -   ---charWidth :: FromPtSize u -          => CharWidthTable u -> EscapedChar -> AdvanceVec u-charWidth fn (CharLiteral c) = fn $ ord c-charWidth fn (CharEscInt i)  = fn i-charWidth fn (CharEscName s) = fn ix-  where-    ix = fromMaybe (-1) $ Map.lookup s ps_glyph_indices
src/Wumpus/Drawing/VersionNumber.hs view
@@ -23,7 +23,7 @@  -- | Version number ----- > (0,1,0)+-- > (0,2,0) -- wumpus_drawing_version :: (Int,Int,Int)-wumpus_drawing_version = (0,1,0)+wumpus_drawing_version = (0,2,0)
wumpus-drawing.cabal view
@@ -1,5 +1,5 @@ name:             wumpus-drawing-version:          0.1.0+version:          0.2.0 license:          BSD3 license-file:     LICENSE copyright:        Stephen Tetley <stephen.tetley@gmail.com>@@ -38,6 +38,16 @@   .   Changelog:   .+  v0.1.0 to 0.2.0:+  .+  * Added new Shapes.+  .+  * Move Geometry modules to Wumpus-Basic.+  .+  * Re-implemented Chains.+  .+  * Re-implemented LR-Text. Added CatText.+  .   v0.1.0:   .   * Initial release - this is a split from @Wumpus-Basic@ making @@ -73,7 +83,8 @@   demo/FontPic.hs,   demo/LeftRightText.hs,   demo/PetriNet.hs,-  demo/PictureCompo.hs,+  demo/SingleLine.hs,+  demo/SampleShapes.hs,   demo/Symbols.hs,   demo/TableChains.hs @@ -81,11 +92,9 @@   hs-source-dirs:     src   build-depends:      base            <  5,                        containers      >= 0.3     && <= 0.6,-                      directory       >= 1.0     && <  2.0, -                      filepath        >= 1.1     && <  2.0,                       vector-space    >= 0.6     && <  1.0,-                      wumpus-core     >= 0.42.0  && <  0.43.0,-                      wumpus-basic    == 0.15.0+                      wumpus-core     >= 0.43.0  && <  0.44.0,+                      wumpus-basic    == 0.16.0       exposed-modules:@@ -99,8 +108,7 @@     Wumpus.Drawing.Colour.X11Colours,     Wumpus.Drawing.Dots.AnchorDots,     Wumpus.Drawing.Dots.Marks,-    Wumpus.Drawing.Geometry.Intersection,-    Wumpus.Drawing.Geometry.Paths,+    Wumpus.Drawing.Grids,     Wumpus.Drawing.Paths,     Wumpus.Drawing.Paths.Base,     Wumpus.Drawing.Paths.Connectors,@@ -111,7 +119,17 @@     Wumpus.Drawing.Shapes.Circle,     Wumpus.Drawing.Shapes.Diamond,     Wumpus.Drawing.Shapes.Ellipse,+    Wumpus.Drawing.Shapes.InvSemicircle,+    Wumpus.Drawing.Shapes.InvSemiellipse,+    Wumpus.Drawing.Shapes.InvTriangle,+    Wumpus.Drawing.Shapes.Parallelogram,     Wumpus.Drawing.Shapes.Rectangle,+    Wumpus.Drawing.Shapes.Trapezium,+    Wumpus.Drawing.Shapes.Semicircle,+    Wumpus.Drawing.Shapes.Semiellipse,+    Wumpus.Drawing.Shapes.Triangle,+    Wumpus.Drawing.Text.Base,+    Wumpus.Drawing.Text.CatText,     Wumpus.Drawing.Text.LRText,     Wumpus.Drawing.Text.SafeFonts,     Wumpus.Drawing.Turtle.TurtleClass,