{-# LANGUAGE PatternGuards #-}-- | Represents an integral rectangular area of the 2D plane.-- Using `Int`s (instead of `Float`s) for the bounds means we can safely-- compare extents for equality.moduleGraphics.Gloss.Data.Extent(Extent,Coord,makeExtent,takeExtent,squareExtent,sizeOfExtent,isUnitExtent,coordInExtent,pointInExtent,centerCoordOfExtent,cutQuadOfExtent,quadOfCoord,pathToCoord,intersectSegExtent,touchesSegExtent)whereimportGraphics.Gloss.Data.PointimportGraphics.Gloss.Data.QuadimportGraphics.Gloss.Geometry.LineimportData.Maybe-- | A rectangular area of the 2D plane.-- We keep the type abstract to ensure that invalid extents cannot be-- constructed.dataExtent=ExtentIntIntIntIntderiving(Eq,Show)-- | An integral coordinate.typeCoord=(Int,Int)-- | Construct an extent.-- The north value must be > south, and east > west, else `error`.makeExtent::Int-- ^ y max (north)->Int-- ^ y min (south)->Int-- ^ x max (east)->Int-- ^ x min (west)->ExtentmakeExtentnsew|n>=s,e>=w=Extentnsew|otherwise=error"Graphics.Gloss.Geometry.Extent.makeExtent: invalid extent"-- | Take the NSEW components of an extent.takeExtent::Extent->(Int,Int,Int,Int)takeExtent(Extentnsew)=(n,s,e,w)-- | A square extent of a given size.squareExtent::Int->ExtentsquareExtenti=Extenti0i0-- | Get the width and height of an extent.sizeOfExtent::Extent->(Int,Int)sizeOfExtent(Extentnsew)=(e-w,n-s)-- | Check if an extent is a square with a width and height of 1.isUnitExtent::Extent->BoolisUnitExtentextent=sizeOfExtentextent==(1,1)-- | Check whether a coordinate lies inside an extent.coordInExtent::Extent->Coord->BoolcoordInExtent(Extentnsew)(x,y)=x>=w&&x<e&&y>=s&&y<n-- | Check whether a point lies inside an extent.pointInExtent::Extent->Point->BoolpointInExtent(Extentnsew)(x,y)=letn'=fromIntegralns'=fromIntegralse'=fromIntegralew'=fromIntegralwinx>=w'&&x<=e'&&y>=s'&&y<=n'-- | Get the coordinate that lies at the center of an extent.centerCoordOfExtent::Extent->(Int,Int)centerCoordOfExtent(Extentnsew)=(w+(e-w)`div`2,s+(n-s)`div`2)-- | Cut one quadrant out of an extent.cutQuadOfExtent::Quad->Extent->ExtentcutQuadOfExtentquad(Extentnsew)=lethheight=(n-s)`div`2hwidth=(e-w)`div`2incasequadofNW->Extentn(s+hheight)(e-hwidth)wNE->Extentn(s+hheight)e(w+hwidth)SW->Extent(n-hheight)s(e-hwidth)wSE->Extent(n-hheight)se(w+hwidth)-- | Get the quadrant that this coordinate lies in, if any.quadOfCoord::Extent->Coord->MaybeQuadquadOfCoordextentcoord=listToMaybe$filter(\q->coordInExtent(cutQuadOfExtentqextent)coord)$allQuads-- | Constuct a path to a particular coordinate in an extent.pathToCoord::Extent->Coord->Maybe[Quad]pathToCoordextentcoord|isUnitExtentextent=Just[]|otherwise=doquad<-quadOfCoordextentcoordrest<-pathToCoord(cutQuadOfExtentquadextent)coordreturn$quad:rest-- | If a line segment (P1-P2) intersects the outer edge of an extent then-- return the intersection point, that is closest to P1, if any.-- If P1 is inside the extent then `Nothing`.---- @-- P2-- /-- ----/--- | / |-- + |-- /-------- / -- P1-- @-- intersectSegExtent::Point->Point->Extent->MaybePointintersectSegExtentp1@(x1,y1)p2(Extentn's'e'w')-- starts below extent|y1<s,Justpos<-intersectSegHorzSegp1p2swe=Justpos-- starts above extent|y1>n,Justpos<-intersectSegHorzSegp1p2nwe=Justpos-- starts left of extent|x1<w,Justpos<-intersectSegVertSegp1p2wsn=Justpos-- starts right of extent|x1>e,Justpos<-intersectSegVertSegp1p2esn=Justpos-- must be starting inside extent.|otherwise=Nothingwheren=fromIntegraln's=fromIntegrals'e=fromIntegrale'w=fromIntegralw'-- | Check whether a line segment's endpoints are inside an extent, or if it-- intersects with the boundary.touchesSegExtent::Point->Point->Extent->BooltouchesSegExtentp1p2extent=pointInExtentextentp1||pointInExtentextentp2||isJust(intersectSegExtentp1p2extent)