---------------------------------------------------------------------- |-- Module : Graphics.SVG.ReadPath-- Copyright : (c) 2011 Tillmann Vogt-- License : BSD3---- Maintainer: Tillmann Vogt <tillk.vogt@googlemail.com>-- Stability : stable-- Portability: portable---- parsing the SVG path command, see <http://www.w3.org/TR/SVG/paths.html#PathData> :moduleGraphics.SVGFonts.ReadPath(pathFromString,PathCommand(..),)whereimportText.ParserCombinators.Parsechiding(spaces)importText.ParserCombinators.Parsec.ExprimportText.ParserCombinators.Parsec.PrimimportqualifiedText.ParserCombinators.Parsec.TokenasPimportText.ParserCombinators.Parsec.Language(emptyDef)importSystem.IO.Unsafe(unsafePerformIO)importDebug.TracetypeX=DoubletypeY=DoubletypeF2=(X,Y)typeTup=(X,Y)typeX1=XtypeY1=YtypeX2=XtypeY2=YdataPathCommand=M_absTup|-- ^Establish a new current point (with absolute coords)M_relTup|-- ^Establish a new current point (with coords relative to the current point)Z|-- ^Close current subpath by drawing a straight line from current point to current subpath's initial pointL_absTup|-- ^A line from the current point to Tup which becomes the new current pointL_relTup|H_absX|-- ^A horizontal line from the current point (cpx, cpy) to (x, cpy)H_relX|V_absY|-- ^A vertical line from the current point (cpx, cpy) to (cpx, y)V_relY|C_abs(X1,Y1,X2,Y2,X,Y)|-- ^Draws a cubic Bézier curve from the current point to (x,y) using (x1,y1) as the-- ^control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve.C_rel(X1,Y1,X2,Y2,X,Y)|S_abs(X2,Y2,X,Y)|-- ^Draws a cubic Bézier curve from the current point to (x,y). The first control point is-- assumed to be the reflection of the second control point on the previous command relative to the current point.-- (If there is no previous command or if the previous command was not an C, c, S or s, assume the first control-- point is coincident with the current point.) (x2,y2) is the second control point (i.e., the control point at-- the end of the curve).S_rel(X2,Y2,X,Y)|Q_abs(X1,Y1,X,Y)|-- ^A quadr. Bézier curve from the curr. point to (x,y) using (x1,y1) as the control pointQ_rel(X1,Y1,X,Y)|-- ^Nearly the same as cubic, but with one point lessT_absTup|-- ^T_Abs = Shorthand/smooth quadratic Bezier curvetoT_relTup|A_abs|-- ^A = Elliptic arc (not used)A_relderivingShow-- | convert a SVG path string into a list of commandspathFromString::String->IO[PathCommand]pathFromStringstr=do{case(parsepath""str)ofLefterr->do{putStr"parse error at ";printerr;return[]}Rightx->returnx}spaces=skipManyspacepath::Parser[PathCommand]path=do{l<-manypathElement;eof;return(concatl)}pathElement::Parser[PathCommand]pathElement=do{whiteSpace;do{symbol"M";l<-many1tupel2;return(map(\x->M_absx)l)}<|>do{symbol"m";l<-many1tupel2;return(map(\x->M_relx)l)}<|>do{symbol"z";return[Z];}<|>do{symbol"Z";return[Z];}<|>do{symbol"L";l<-many1tupel2;return(map(\x->L_absx)l)}<|>do{symbol"l";l<-many1tupel2;return(map(\x->L_relx)l)}<|>do{symbol"H";l<-many1myfloat;return(map(\x->H_abs(realToFracx))l)}<|>do{symbol"h";l<-many1myfloat;return(map(\x->H_rel(realToFracx))l)}<|>do{symbol"V";l<-many1myfloat;return(map(\x->V_abs(realToFracx))l)}<|>do{symbol"v";l<-many1myfloat;return(map(\x->V_rel(realToFracx))l)}<|>do{symbol"C";l<-many1tupel6;return(map(\x->C_absx)l)}<|>do{symbol"c";l<-many1tupel6;return(map(\x->C_relx)l)}<|>do{symbol"S";l<-many1tupel4;return(map(\x->S_absx)l)}<|>do{symbol"s";l<-many1tupel4;return(map(\x->S_relx)l)}<|>do{symbol"Q";l<-many1tupel4;return(map(\x->Q_absx)l)}<|>do{symbol"q";l<-many1tupel4;return(map(\x->Q_relx)l)}<|>do{symbol"T";l<-many1tupel2;return(map(\x->T_absx)l)}<|>do{symbol"t";l<-many1tupel2;return(map(\x->T_relx)l)}<|>do{symbol"A";l<-many1tupel2;return(map(\x->A_abs)l)}<|>-- not useddo{symbol"a";l<-many1tupel2;return(map(\x->A_rel)l)}-- not used}comma=do{spaces;try(do{(char',');return()})<|>spaces}tupel2::Parser(X,Y)tupel2=do{x<-myfloat;comma;y<-myfloat;spaces;return(realToFracx,realToFracy)}tupel4::Parser(X,Y,X,Y)tupel4=do{x1<-myfloat;comma;y1<-myfloat;spaces;x<-myfloat;comma;y<-myfloat;spaces;return(realToFracx1,realToFracy1,realToFracx,realToFracy)}tupel6::Parser(X,Y,X,Y,X,Y)tupel6=do{x1<-myfloat;comma;y1<-myfloat;spaces;x2<-myfloat;comma;y2<-myfloat;spaces;x<-myfloat;comma;y<-myfloat;spaces;return(realToFracx1,realToFracy1,realToFracx2,realToFracy2,realToFracx,realToFracy)}myfloat=try(do{symbol"-";n<-float;return(negaten)})<|>tryfloat<|>-- 0 is not recognized as a float, so recognize it as an integer and then convert to floatdo{i<-integer;return(fromIntegrali)}lexer=P.makeTokenParseremptyDefwhiteSpace=P.whiteSpacelexersymbol=P.symbollexerinteger=P.integerlexerfloat=P.floatlexer