-- |-- Module: Graphics.Chalkboard.Utils-- Copyright: (c) 2009 Andy Gill-- License: BSD3---- Maintainer: Andy Gill <andygill@ku.edu>-- Stability: unstable-- Portability: ghc---- This module contains some general utilties.--moduleGraphics.Chalkboard.Utils(-- * Utilties for @R@.innerSteps,outerSteps,fracPart,fromPolar,toPolar,angleOfLine-- * Pointwise operators.,interpBool,sampleUI,withMask,withDefault,choose-- * Point Utilties.,insideRegion,insideCircle,distance,intervalOnLine,circleOfDots)whereimportGraphics.Chalkboard.Types-------------------------------------------------------------------------------- | innerSteps takes n even steps from 0 .. 1, by not actually touching 0 or 1.-- The first and last step are 1/2 the size of the others, so that repeated innerSteps-- can be tiled neatly.innerSteps::Int->[R]innerStepsn=map(/fromIntegral(n*2))(mapfromIntegral(taken[1::Int,3..]))-- | outerSteps takes n even steps from 0 .. 1, starting with 0, and ending with 1,-- returning n+1 elements.outerSteps::Int->[R]outerStepsn=map(/fromIntegraln)(mapfromIntegral(take(n+1)[(0::Int)..]))-- | Extract the fractional part of an @R@.fracPart::R->RfracPartx=x-fromIntegral((floorx)::Integer)-------------------------------------------------------------------------------- Pointwise operators-- | Covert a Bool (mask point) into a unit interval.interpBool::Bool->UIinterpBoolTrue=1.0interpBoolFalse=0.0-- | sample a UI, giving a point of a mask.sampleUI::UI->BoolsampleUIn=n>=0.5-- | Use a mask to create a Just value, or Nothing.withMask::a->(Bool->Maybea)withMaskaTrue=JustawithMask_False=Nothing-- | With a default if you do not have a Just.withDefault::a->(Maybea->a)withDefaultaNothing=awithDefault_(Justb)=b-- | 'choose' between two values.choose::a->a->(Bool->a)chooset_fTrue=tchoose_tfFalse=f--------------------------------------- Point operations-- | is a @Point@ inside a region?insideRegion::(Point,Point)->Point->BoolinsideRegion((x1,y1),(x2,y2))(x,y)=x1<=x&&x<=x2&&y1<=y&&y<=y2-- | is a @Point@ inside a circle, where the first two arguments are the center of the circle,-- and the radius.insideCircle::Point->R->Point->BoolinsideCircle(x1,y1)r(x,y)=distance(x1,y1)(x,y)<=r-- | What is the 'distance' between two points in R2?-- This is optimised for the normal form @distance p1 p2 <= v@, which avoids using @sqrt@.distance::Point->Point->Rdistance(x,y)(x',y')=sqrt(xd*xd+yd*yd)wherexd=x-x'yd=y-y'{-# INLINE distance #-}-- The obvious sqrt (x * x) ==> x does not fire. {-# RULES "distance <= w" forall t u w . distance t u <= w = distanceLe t u w #-}{-# INLINE distanceLe #-}distanceLe::Point->Point->R->BooldistanceLe(x,y)(x',y')w=(xd*xd+yd*yd)<=w*wwherexd=x-x'yd=y-y'-- | 'intervalOnLine' find the place on a line (between 0 and 1) that is closest to the given point.intervalOnLine::(Point,Point)->Point->RintervalOnLine((x1,y1),(x2,y2))(x0,y0)=((x0-x1)*(x2-x1)+(y0-y1)*(y2-y1))/(xd*xd+yd*yd)wherexd=x2-x1yd=y2-y1fromPolar::(R,Radian)->PointfromPolar(p,phi)=(p*cosphi,p*sinphi)toPolar::Point->(R,Radian)toPolar(x,y)=(x*x+y*y,atan2xy)angleOfLine::(Point,Point)->RadianangleOfLine((x1,y1),(x2,y2))=atan2(x2-x1)(y2-y1)-- | circleOfDots generates a set of points between (-1..1,-1..1), inside a circle.circleOfDots::Int->[Point]circleOfDots0=error"circleOfDots 0"circleOfDotsn=[(x,y)|x<-map(\t->t*2-1)$outerStepsn,y<-map(\t->t*2-1)$outerStepsn,(x*x+y*y)<=1.0]