{"id":41,"date":"2007-08-05T21:26:40","date_gmt":"2007-08-06T04:26:40","guid":{"rendered":"http:\/\/www.elbeno.com\/haskell_soe_blog\/?p=41"},"modified":"2008-01-08T07:14:05","modified_gmt":"2008-01-08T15:14:05","slug":"exercise-812","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/haskell_soe_blog\/?p=41","title":{"rendered":"Exercise 8.12"},"content":{"rendered":"<p>There are a couple of ways to do this (the basic problem being how to deal with concave polygons). One way is to convert the polygon to a convex hull and a list of triangles representing subtractions from the convex hull, then check containment within the hull and non-containment within the triangles. However, I present a simpler way: pick a point guaranteed not to be in the polygon, form the ray between that and the point in question, and count the number of times that ray crosses the polygon sides. If it&#8217;s even, the point is outside the polygon. This method also works for self-crossing polygons (provided that one considers any internal spaces formed as outside the polygon: consider a pentagram for example).<\/p>\n<pre lang=\"haskell\">raysCross :: Ray -> Ray -> Bool\r\nraysCross (a,b) (x,y) = let h = isLeftOf x (a,b) && isRightOf y (a,b)\r\n                            i = isLeftOf y (a,b) && isRightOf x (a,b)\r\n                            j = isLeftOf a (x,y) && isRightOf b (x,y)\r\n                            k = isLeftOf b (x,y) && isRightOf a (x,y)\r\n                        in (h || i) && (j || k)\r\n\r\ncountCrossings :: Ray -> [Ray] -> Int\r\ncountCrossings r rs = foldl (+) 0\r\n                      (map (\\x -> if raysCross r x then 1 else 0) rs)\r\n\r\nguaranteedOutside :: [Vertex] -> Vertex\r\nguaranteedOutside vs\r\n    = (foldl maxop 0 xs + 1, foldl maxop 0 ys + 1)\r\n    where (xs, ys) = unzip vs\r\n          maxop a b = if a > b then a else b\r\n\r\ncontainsS' :: Shape -> Coordinate -> Bool\r\n(Polygon ps) `containsS'` p\r\n    = let poutside = guaranteedOutside ps\r\n      in (countCrossings (p,poutside)\r\n          (zip ps (tail ps ++ [head ps]))) `mod` 2 == 1<\/pre>\n<p>See <a href=\"http:\/\/www.elbeno.com\/haskell_soe_blog\/?p=33\">Exercise 8.4<\/a> for definitions of <tt>isLeftOf<\/tt> and <tt>isRightOf<\/tt>. I am also left feeling that there must be a more elegant way to count the number of list elements that fulfil a predicate (which is what <tt>countCrossings<\/tt> is really doing).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are a couple of ways to do this (the basic problem being how to deal with concave polygons). One way is to convert the polygon to a convex hull and a list of triangles representing subtractions from the convex hull, then check containment within the hull and non-containment within the triangles. However, I present [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=\/wp\/v2\/posts\/41"}],"collection":[{"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=41"}],"version-history":[{"count":0,"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=\/wp\/v2\/posts\/41\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=41"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=41"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/haskell_soe_blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=41"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}