import LSystem {-- Peter Nock s0787028 --} type Coord2d = (Float,Float) type Coord3d = (Float,Float,Float) type Triangle = (Coord3d,Coord3d,Coord3d) --Define some more colours sand = (Colour 1 0.85 0) lightYellow = (Colour 1 0.95 0) -- Set the max draw depth depth = 200 triangleWireframe :: Coord3d -> Coord3d -> Coord3d -> Pen -> Command triangleWireframe (x1,y1,z1) (x2,y2,z2) (x3,y3,z3) colour = makeLine (x1,y1,z1) (x2,y2,z2) colour :#: makeLine (x2,y2,z2) (x3,y3,z3) colour :#: makeLine (x3,y3,z3) (x1,y1,z1) colour triangleFilled :: Coord3d -> Coord3d -> Coord3d -> Pen -> Command triangleFilled (x1,y1,z1) (x2,y2,z2) (x3,y3,z3) colour | x1 == x2 = Sit | x1 > x2 = makeLine (x1,y1,z1) (x2,y2,z2) colour :#: makeLine (x2,y2,z2) (x3,y3,z3) colour :#: makeLine (x3,y3,z3) (x1,y1,z1) colour :#: triangleFilled (x1-1,y1,z1) (x2,y2,z2) (x3,y3,z3) colour | x1 < x2 = makeLine (x1,y1,z1) (x2,y2,z2) colour :#: makeLine (x2,y2,z2) (x3,y3,z3) colour :#: makeLine (x3,y3,z3) (x1,y1,z1) colour :#: triangleFilled (x1,y1,z1) (x2-1,y2,z2) (x3,y3,z3) colour | otherwise = Sit drawTriangle :: Coord3d -> Coord3d -> Coord3d -> Pen -> Command drawTriangle (x1,y1,z1) (x2,y2,z2) (x3,y3,z3) colour = triangleFilled (x1,y1,z1) (x2,y2,z2) (x3,y3,z3) colour makeLine :: Coord3d -> Coord3d -> Pen -> Command makeLine (x1,y1,z1) (x2,y2,z2) colour | x1 == x2 = Branch (moveBy (x1fixed,y1fixed,z1fixed) :#: Turn (fromRadian turn) :#: GrabPen colour :#: Go (y2fixed-y1fixed)) | y1 == y2 = Branch (moveBy (x1fixed,y1fixed,z1fixed) :#: Turn (fromRadian turn) :#: GrabPen colour :#: Go (x2fixed-x1fixed)) | otherwise = Branch (moveBy (x1fixed,y1fixed,z1fixed) :#: Turn (fromRadian turn) :#: GrabPen colour :#: Go ((x1fixed-x2fixed)/sin(turn))) where turn :: Float turn = (angleFromPoints ((x1fixed-x2fixed),(y1fixed-y2fixed))) (x1fixed,y1fixed,z1fixed) = fixPosition (x1,y1,z1) depth (x2fixed,y2fixed,z2fixed) = fixPosition (x2,y2,z2) depth rectangleWireframe :: Coord3d -> Coord3d -> Pen -> Command rectangleWireframe (x1,y1,z1) (x2,y2,z2) colour = triangleWireframe (x1,y1,z1) (x2,y2,z2) (x2,y1,((z2+z1)/2)) colour :#: triangleWireframe (x1,y1,z1) (x2,y2,z2) (x1,y2,((z2+z1)/2)) colour rectangleFilled :: Coord3d -> Coord3d -> Pen -> Command rectangleFilled (x1,y1,z1) (x2,y2,z2) colour = triangleFilled (x1,y1,z1) (x2,y2,z2) (x2,y1,((z2+z1)/2)) colour :#: triangleFilled (x1,y1,z1) (x2,y2,z2) (x1,y2,((z2+z1)/2)) colour makeRectangle :: Coord3d -> Coord3d -> Pen -> Command makeRectangle (x1,y1,z1) (x2,y2,z2) colour = rectangleFilled (x1,y1,z1) (x2,y2,z2) colour moveBy :: Coord3d -> Command moveBy (x1,y1,z1) = GrabPen Inkless :#: Go y1 :#: Turn 270 :#: Go x1 :#: Turn 90 :#: GrabPen black -- Calculate the angle between (0,0) and (x,y) angleFromPoints :: Coord2d -> Angle angleFromPoints (0,y) = 0 angleFromPoints (x,0) = (2*pi - pi/2) angleFromPoints (x,y) = (2*pi - atan(x/y)) fixPosition :: Coord3d -> Float -> Coord3d fixPosition (x,y,0) maxDepth = (x,y,0) fixPosition (x,y,z) maxDepth = (x2,y2,0) where y2 = y x2 = x * (maxDepth - z) / maxDepth -- Convert from radians to degrees fromRadian :: Float -> Float fromRadian radians = radians * (180/pi) -- Convert from degrees to radians fromDegree :: Float -> Float fromDegree degrees = pi * degrees / 180 makeScene :: Coord3d -> Command makeScene (xOffset,yOffset,zOffset) = triangleWireframe (40,100,0) (-100,-10,0) (-60,-60,0) red :#: triangleWireframe (40,100,20) (-100,-10,20) (-60,-60,20) red loadARectangles :: Int -> Command loadARectangles number = join ( [ Branch (rectangleWireframe (x,-30,0) (x+30,10,50) red) | x <- [(-400),(-350)..400] ] ) go = display 1.0 (startDisplay (0,0,0)) startDisplay :: Coord3d -> Command startDisplay (xOffset,yOffset,zOffset) = makeSky :#: makeSea :#: makeIslands :#: makeTrees makeSky =join [ Branch (makeLine (-400,460-x/2,0) (400,460-x/2,0) (Colour 0.1 (x/1000) (200/255))) | x <- [60..880] ] makeSea = join [ Branch (makeLine (-400,-530+x/2,0) (400,-530+x/2,0) (Colour 0 (x/1180) (160/255))) | x <- [100..1100] ] makeIslands = makeIsland (-400) 600 (-50) 40 :#: makeIsland (400) 300 (-300) 40 makeIsland left width base height = Branch (moveBy (left,base,0) :#: Turn 270 :#: GrabPen sand :#: (join [ Go (width -x/2) :#: Turn 90 :#: Go 1 :#: Turn 90 :#: Go (width) :#: Turn 270 :#: Go 1 :#: Turn 270 | x <- [1..height] ])) makeTrees = Branch (moveBy (-50,-0,0) :#: makeTree 7) :#: Branch (moveBy (-200,0,0) :#: makeTree 8) :#: Branch (moveBy (80,-45,0) :#: makeTree 5) :#: Branch (moveBy (-100,-50,0) :#: makeTree 4) :#: Branch (moveBy (180,-240,0) :#: makeTree 4) makeTree height = makeTreeTrunk height :#: makeLeaves height where makeTreeTrunk height = join [ makeRectangle (-(height-x)*2-3,5*x,15*(x-1)) ((height-x)+height,8+15*x,15*x) lightYellow | x <- [1..height] ] makeLeaves height = join [ makeLeaf height (x*3) | x <- [-6..6] ] makeLeaf height angle = Branch (moveBy (-3,height*15,0) :#: join [ GrabPen Inkless :#: Go (2.4*x) :#: GrabPen (Colour 0.0 (1-x/20) 0.2) :#: Turn angle :#: makeRectangle (0,0,0) (height,3*x,15*x) (Colour 0.0 (1-x/20) 0.2) | x <- [1..(height+2)] ]) --Join join :: [Command] -> Command join [] = Sit join (x:[]) = x join (x:xs) = x :#: join xs -- Split split :: Command -> [Command] split (x :#: xs) = split x ++ split xs split x = [x]