update
[fp1415-soccerfun.git] / src / Gui / renderGameFixCamera.icl
1 implementation module renderGameFixCamera
2
3 import Geometry
4 import render
5
6 renderFixCamera :: RenderStyle
7 renderFixCamera = { name = "Fixed camera"
8 , look = fixcamera
9 }
10
11 fixcamera :: !Match !SelectState !UpdateState !*Picture -> *Picture
12 fixcamera match=:{theField,theBall,team1,team2} _ updSt=:{newFrame} picture
13 # picture = setPenColour Black picture
14 # picture = fill newFrame picture // erase entire background
15 # picture = setPenColour green picture
16 # picture = drawField picture // draw the field and outer lines
17 # picture = drawMiddleArea picture // middle line, circle and spot
18 # picture = drawGoalAreas picture // goal areas
19 # picture = drawPenaltyAreas picture // penalty areas
20 # picture = drawCornerAreas picture // corner areas
21 # picture = drawGoals picture // goals
22 # picture = foldr drawPlayer picture sorted_players // players
23 # picture = drawBall (getFootball theBall (team1 ++ team2)) picture // football
24 = picture
25 where
26 {w,h} = rectangleSize newFrame
27 {fwidth,flength} = theField
28 ratio = min ((toReal w) / (toReal flength)) ((toReal h) / (toReal fwidth))
29 pix x = toInt (ratio * toReal x) // convert metres to pixels
30 ppix {px,py} = {x = pix px, y = pix py} // convert Position to pixels
31 (northPole,southPole) = goal_poles theField
32 fieldfit = min (toReal w / (ratio * (convertToIsoXNormal (toReal flength) 0.0 - convertToIsoXNormal 0.0 (toReal fwidth))))
33 (toReal h / (ratio * (convertToIsoYNormal (toReal flength) (toReal fwidth) - convertToIsoYNormal 0.0 0.0)))
34 north_west = ppix (convertToIso {px = zero, py = zero })
35 north_east = ppix (convertToIso {px = flength, py = zero })
36 south_east = ppix (convertToIso {px = flength, py = fwidth})
37 south_west = ppix (convertToIso {px = zero, py = fwidth})
38 sorted_players = let se = {px=scale 0.5 flength, py=scale -0.5 fwidth}
39 in sortBy (\(_,fb1) (_,fb2) -> dist fb1 se < dist fb2 se) ([(WestColour,fb) \\ fb <- team1] ++ [(EastColour,fb) \\ fb <- team2])
40
41 drawPlayer :: !(!Colour, !Footballer) !*Picture -> *Picture
42 drawPlayer (colour, fb=:{playerID ,name,nose=nose_dir,effect,pos=pos`}) picture
43 # picture = drawName name picture
44 | perhaps isOnTheGround effect = drawGroundPlayer fb picture
45 | otherwise = drawStandingPlayer fb picture
46 where
47 pos = move_point {dx=scale 0.5 flength, dy=scale 0.5 fwidth} {pos` & py = ~pos`.py}
48 player_width = m 0.5
49 body_circle = circle (pix player_width)
50 bearing_circle = circle (pix (m 0.3))
51 nose_dir_point k = move_point (scale k (convertToIsoVector {dx = m (cosinus nose_dir), dy = m (~(sinus nose_dir))})) (convertToIso pos)
52
53 drawName name picture
54 # picture = setPenColour White picture
55 # picture = drawAt (ppix (move_point one (convertToIso pos))) name picture
56 = picture
57
58 drawGroundPlayer fb=:{length} picture
59 # (w,picture) = getPenSize picture
60 # picture = setPenSize (pix player_width + 2) picture
61 # picture = setPenColour Black picture
62 # picture = draw (body_line offset) picture
63 # picture = setPenSize (pix player_width) picture
64 # picture = setPenColour colour picture
65 # picture = draw (body_line zero) picture
66 # picture = setPenSize w picture
67 # picture = fillAt (ppix (nose_dir_point (toReal length + 0.2))) bearing_circle picture
68 # picture = setPenColour Black picture
69 # picture = drawAt (ppix (nose_dir_point (toReal length + 0.2))) bearing_circle picture
70 = picture
71 where
72 offset = {vx = -1, vy = -1}
73 body_line v = { line_end1 = movePoint v (ppix (convertToIso pos))
74 , line_end2 = movePoint v (ppix (nose_dir_point (toReal length)))
75 }
76
77 drawStandingPlayer fb=:{length} picture
78 # picture = setPenColour colour picture
79 # picture = fillAt (ppix (nose_dir_point 1.0)) bearing_circle picture // nose direction
80 # picture = foldr (uncurry fillAt) picture playerCorpus
81 # picture = setPenColour Black picture
82 # picture = drawAt (ppix (nose_dir_point 1.0)) bearing_circle picture // surrounding circle
83 # picture = foldr (uncurry drawAt) picture playerCorpus
84 = picture
85 where
86 player_width` = toReal player_width
87 length` = pix length
88 (up,down) = ({vx = 0, vy = ~length`}, {vx = 0,vy = length`})
89 playerCorpus = [(ptl,{polygon_shape = [up,{vx = ptr.x-ptl.x, vy = ptr.y-ptl.y},down]})
90 ,(pbl,{polygon_shape = [up,{vx = pbr.x-pbl.x, vy = pbr.y-pbl.y},down]})
91 ,(pbr,{polygon_shape = [up,{vx = ptr.x-pbr.x, vy = ptr.y-pbr.y},down]})
92 ,(pbl,{polygon_shape = [up,{vx = ptl.x-pbl.x, vy = ptl.y-pbl.y},down]})
93 ]
94 playerRadius = m (sqrt (player_width` * player_width` + player_width` * player_width`))
95 add_angle a = let c = cosinus (a + nose_dir)
96 s = sinus (a + nose_dir)
97 in ppix (convertToIso (move_point {dx = scale c playerRadius, dy = scale s playerRadius} pos))
98 ptr = add_angle (rad (0.25*pi))
99 ptl = add_angle (rad (0.75*pi))
100 pbl = add_angle (rad (1.25*pi))
101 pbr = add_angle (rad (1.75*pi))
102
103 drawMiddleArea :: !*Picture -> *Picture
104 drawMiddleArea picture
105 # picture = drawLine {x = (north_west.x+north_east.x)/2, y = (north_west.y+north_east.y)/2}
106 {x = (south_west.x+south_east.x)/2, y = (south_west.y+south_east.y)/2} picture // middle line
107 # picture = drawAt center (circle (pix (scale fieldfit radius_centre_spot))) picture // centre spot
108 # picture = drawAt centerRadius {polygon_shape = circle_vs} picture // centre circle
109 = picture
110 where
111 center = {x = sum [north_west.x,north_east.x,south_west.x,south_east.x] / 4
112 ,y = sum [north_west.y,north_east.y,south_west.y,south_east.y] / 4
113 }
114 centerRadius = ppix (convertToIso {px = scale 0.5 flength, py = scale 0.5 fwidth - radius_centre_circle}) // centre circle starting location for drawing
115 start = {px=radius_centre_circle, py=zero} // starting location for generating circle points
116 circle_vs = circle_shape radius_centre_circle (rad (0.025*pi)) (rad (2.0*pi)) start zero []
117
118 drawGoals :: !*Picture -> *Picture
119 drawGoals picture
120 # picture = drawLine (ppix ne) (ppix (addGoalHeight ne)) picture // east north pole
121 # picture = drawLine (ppix se) (ppix (addGoalHeight se)) picture // east south pole
122 # picture = drawLine (ppix (addGoalHeight ne)) (ppix (addGoalHeight se)) picture // east pole connect
123 # picture = drawLine (ppix nw) (ppix (addGoalHeight nw)) picture // west north pole
124 # picture = drawLine (ppix sw) (ppix (addGoalHeight sw)) picture // west south pole
125 # picture = drawLine (ppix (addGoalHeight nw)) (ppix (addGoalHeight sw)) picture // west pole connect
126 = picture
127 where
128 addGoalHeight p = move_point {zero & dy = ~goal_height} p
129 nw = convertToIso {px = zero, py = northPole + scale 0.5 fwidth}
130 sw = convertToIso {px = zero, py = southPole + scale 0.5 fwidth}
131 ne = convertToIso {px = flength, py = northPole + scale 0.5 fwidth}
132 se = convertToIso {px = flength, py = southPole + scale 0.5 fwidth}
133
134 drawField :: !*Picture -> *Picture
135 drawField picture
136 # picture = fillAt north_west field_shape picture //field
137 # picture = setPenColour White picture
138 # picture = drawAt north_west field_shape picture //outline
139 = picture
140 where
141 field_shape = {polygon_shape = [{vx = north_east.x-north_west.x, vy = north_east.y-north_west.y}
142 ,{vx = south_east.x-north_east.x, vy = south_east.y-north_east.y}
143 ,{vx = south_west.x-south_east.x, vy = south_west.y-south_east.y}
144 ]
145 }
146
147 drawBall :: !Football !*Picture -> *Picture
148 drawBall football picture
149 # picture = setPenColour ball_colour picture
150 # picture = drawAt (ppix ballPosition) ball picture // ball shadow
151 # picture = fillAt (ppix elevation) ball picture // ball
152 # picture = setPenColour White picture
153 # picture = drawAt (ppix elevation) ball picture // ball-line
154 = picture
155 where
156 groundPos` = football.ballPos.pxy
157 groundPos = {groundPos` & py = ~groundPos`.py}
158 ballPosition = convertToIso (move_point {dx=scale 0.5 flength,dy=scale 0.5 fwidth} groundPos)
159 elevation = move_point {zero & dy=scale (~fieldfit) football.ballPos.pz} ballPosition
160 ball = circle (pix (scale 2.8 radius_football))
161
162 drawGoalAreas :: !*Picture -> *Picture
163 drawGoalAreas picture
164 # picture = drawLine (ppix (convertToIso {px = flength,py = y_north})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east north edge
165 # picture = drawLine (ppix (convertToIso {px = flength,py = y_south})) (ppix (convertToIso {px = x_east, py = y_south})) picture // east south edge
166 # picture = drawLine (ppix (convertToIso {px = x_east, py = y_south})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east edge
167 # picture = drawLine (ppix (convertToIso {px = zero, py = y_north})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west north edge
168 # picture = drawLine (ppix (convertToIso {px = zero, py = y_south})) (ppix (convertToIso {px = x_west, py = y_south})) picture // west south edge
169 # picture = drawLine (ppix (convertToIso {px = x_west, py = y_south})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west edge
170 = picture
171 where
172 (y_north,y_south) = (scale 0.5 fwidth + goal_area_depth + northPole, scale 0.5 fwidth + southPole - goal_area_depth)
173 (x_west, x_east) = (goal_area_depth, flength - goal_area_depth)
174
175 drawPenaltyAreas :: !*Picture -> *Picture
176 drawPenaltyAreas picture
177 # picture = drawLine (ppix (convertToIso {px = flength,py = y_north})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east north edge
178 # picture = drawLine (ppix (convertToIso {px = flength,py = y_south})) (ppix (convertToIso {px = x_east, py = y_south})) picture // east south edge
179 # picture = drawLine (ppix (convertToIso {px = x_east, py = y_south})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east edge
180 # picture = drawLine (ppix (convertToIso {px = zero, py = y_north})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west north edge
181 # picture = drawLine (ppix (convertToIso {px = zero, py = y_south})) (ppix (convertToIso {px = x_west, py = y_south})) picture // west south edge
182 # picture = drawLine (ppix (convertToIso {px = x_west, py = y_south})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west edge
183 # picture = drawAt (ppix east_spotIso) (circle (pix (scale fieldfit radius_penalty_spot))) picture // east penalty spot
184 # picture = drawAt (ppix (move_point (convertToIsoVector {dx=m (~h_dist),dy=m dyStart}) east_spotIso)) east_curve picture // east curve
185 # picture = drawAt (ppix west_spotIso) (circle (pix (scale fieldfit radius_penalty_spot))) picture // west penalty spot
186 # picture = drawAt (ppix (move_point (convertToIsoVector {dx=m h_dist,dy=m (~dyStart)}) west_spotIso)) west_curve picture // west curve
187 = picture
188 where
189 (y_north,y_south) = (northPole + penalty_area_depth + scale 0.5 fwidth, southPole - penalty_area_depth + scale 0.5 fwidth)
190 (x_west, x_east) = (penalty_area_depth, flength - penalty_area_depth)
191 angle = arccosinus (h_dist / (toReal radius_penalty_area * fieldfit))
192 h_dist = (toReal penalty_area_depth - toReal penalty_spot_depth) * fieldfit
193 east_spotIso = convertToIso {px = flength - penalty_spot_depth, py = scale 0.5 fwidth}
194 west_spotIso = convertToIso {px = penalty_spot_depth, py = scale 0.5 fwidth}
195 circleStartWest = {px = scale (cosinus (angle - rad (0.5*pi))) radius_penalty_area, py = scale (sinus (angle - rad (0.5*pi))) radius_penalty_area}
196 circleStartEast = {px = scale (cosinus (angle + rad (0.5*pi))) radius_penalty_area, py = scale (sinus (angle + rad (0.5*pi))) radius_penalty_area}
197 dyStart = sqrt (rpaff * rpaff - h_dist * h_dist)
198 rpaff = toReal radius_penalty_area * fieldfit
199 east_curve = {polygon_shape = circle_shape radius_penalty_area (rad (pi/180.0)) (rad (0.5*pi) + angle) circleStartEast (rad (0.5*pi) - angle) []}
200 west_curve = {polygon_shape = circle_shape radius_penalty_area (rad (pi/180.0)) (angle - rad (0.5*pi)) circleStartWest (~(angle + rad (0.5*pi))) []}
201
202 drawCornerAreas :: !*Picture -> *Picture
203 drawCornerAreas picture
204 # picture = drawAt (ppix (convertToIso {px = flength - radius_corner_kick_area, py = fwidth})) (corner (rad (1.0*pi) - a1) (rad (0.0*pi) + a1) True ) picture // east south corner
205 # picture = drawAt (ppix (convertToIso {px = radius_corner_kick_area, py = zero })) (corner (rad (2.0*pi) - a1) (rad (1.0*pi) + a1) True ) picture // west north corner
206 # picture = drawAt (ppix (convertToIso {px = radius_corner_kick_area, py = fwidth})) (corner (rad (1.5*pi) + a2) (rad (0.5*pi) - a2) False) picture // west south corner
207 # picture = drawAt (ppix (convertToIso {px = flength - radius_corner_kick_area, py = zero })) (corner (rad (0.5*pi) + a2) (rad (1.5*pi) - a2) False) picture // east north corner
208 = picture
209 where
210 corner f t c = { curve_oval = circle (pix (scale fieldfit radius_corner_kick_area))
211 , curve_from = toReal f
212 , curve_to = toReal t
213 , curve_clockwise = c
214 }
215 (a1,a2) = (arctangens 0.5, arctangens 2.0)
216
217 circle_shape :: !Metre !Angle !Angle !Position !Angle ![Vector2] -> [Vector2]
218 circle_shape r i angle base end vs
219 | angle <= end = reverse vs
220 | otherwise = circle_shape r i (angle-i) this end [{vx = thisIso.x - baseIso.x, vy = baseIso.y - thisIso.y} : vs]
221 where
222 this = {px = scale (cosinus angle) r, py = scale (sinus angle) r}
223 thisIso = ppix (convertToIsoNormal this)
224 baseIso = ppix (convertToIsoNormal base)
225
226 convertToIsoNormal {px,py} = {px = scale fieldfit (px - py + fwidth), py = scale (0.5*fieldfit) (px + py)}
227
228 convertToIso :: !Position -> Position
229 convertToIso pos = { px = scale fieldfit (pos.px - yScaled pos + fwidth)
230 , py = scale (0.5*fieldfit) (pos.px + yScaled pos)
231 }
232
233 yScaled :: !Position -> Metre
234 yScaled pos=:{px, py}
235 | py <= scale 0.5 fwidth = py + scale yscale d
236 | otherwise = py - scale yscale d
237 where
238 yscale = (1.0 - (toReal px)/(toReal flength)) / factor
239 d = abs (py - scale 0.5 fwidth)
240 factor = 8.0
241
242 convertToIsoVector :: !RVector -> RVector
243 convertToIsoVector {dx,dy} = {dx = dx - dy, dy = scale 0.5 (dx+dy)}
244
245 convertToIsoXNormal :: !Real !Real -> Real
246 convertToIsoXNormal x y = x - y
247
248 convertToIsoYNormal :: !Real !Real -> Real
249 convertToIsoYNormal x y = (x + y) / 2.0
250
251 green :== RGB {r=30,g=140,b=40} // dark green works better on a beamer
252 black :== Black // black
253 ball_colour :== Black
254
255 circle r :== {oval_rx=r,oval_ry=r}