-- Paint inside the lines! -- Example which shows how to test if a point is inside a convex polygon -- What is a convex polygon? -- 1) If you roll a convex polygon on flat ground, all of the sides will -- touch the ground at some point. -- 2) If two people are inside a convex polygon playground, they can role a -- ball between them. myShapes model = -- List.map applies the function drawAt to all the positions List.map drawAt model.positions ++ -- draw a polygon with vertices from the list polyList [ polygon polyList |> outlined (solid 1) (rgba 0 255 0 0.5) , text (String.fromInt model.nonHits ++ " misses") |> filled black |> move (40,-50) ] ++ -- to catch taps everywhere, draw a clear rect above all shapes [ rect 192 128 |> filled (rgba 0 0 0 0.01) |> notifyTapAt TapAt ] -- draw a red spot at a point drawAt : (Float,Float) -> Shape Msg drawAt pos = circle 0.5 |> filled red |> move pos type Msg = Tick Float GetKeyState | TapAt (Float,Float) | StartAgain update msg model = case msg of Tick t _ -> { model | time = t } StartAgain -> { model | positions = [] } TapAt pos -> if insideConvexClockwisePoly polyList pos then { model | positions = pos :: model.positions } else { model | nonHits = model.nonHits + 1 } init : { time : Float, positions : List (Float,Float), nonHits : Int } init = { time = 0, positions = [], nonHits = 0 } -- define a region by going clockwise around a convex polygon -- in a convex polygon, stretching a string between any two points on the perimeter stays inside the triangle polyList = [(-10,-20),(-10,20), (20,20), (-10,-20)] -- geometry helper functions -- return True if the point (x,y) is on the right of the line going from (x1,y1) to (x2,y2) onRightOf : (Float,Float) -> (Float,Float) -> (Float,Float) -> Bool onRightOf (x1,y1) (x2,y2) (x,y) = let v12 = (y1 - y2, x2 - x1) vp2 = (x - x2, y - y2 ) in dot v12 vp2 < 0 -- calculate dot product, it is positive if two vectors are pointing in the same direction dot : (Float,Float) -> (Float,Float) -> Float dot (x,y) (u,v) = x*u + y*v insideConvexClockwisePoly : List (Float,Float) -> (Float,Float) -> Bool insideConvexClockwisePoly ptList pt = case ptList of q1 :: q2 :: qs -> if onRightOf q1 q2 pt then insideConvexClockwisePoly (q2 :: qs) pt else False otherwise -> True -- impossible