RosettaCodeData/Task/Ray-casting-algorithm/OCaml/ray-casting-algorithm.ml

98 lines
2.2 KiB
OCaml

type point = { x:float; y:float }
type polygon = {
vertices: point array;
edges: (int * int) list;
}
let p x y = { x=x; y=y }
let square_v = [|
(p 0. 0.); (p 10. 0.); (p 10. 10.); (p 0. 10.);
(p 2.5 2.5); (p 7.5 0.1); (p 7.5 7.5); (p 2.5 7.5)
|]
let esa_v = [|
(p 3. 0.); (p 7. 0.); (p 10. 5.); (p 7. 10.); (p 3. 10.); (p 0. 5.)
|]
let esa = {
vertices = esa_v;
edges = [ (0,1); (1,2); (2,3); (3,4); (4,5); (5,0) ]
}
let square = {
vertices = square_v;
edges = [ (0,1); (1,2); (2,3); (3,0) ]
}
let squarehole = {
vertices = square_v;
edges = [ (0,1); (1,2); (2,3); (3,0); (4,5); (5,6); (6,7); (7,4) ]
}
let strange = {
vertices = square_v;
edges = [ (0,4); (4,3); (3,7); (7,6); (6,2); (2,1); (1,5); (5,0) ]
}
let min_y ~a ~b = if a.y > b.y then (b) else (a)
let coeff_ang ~pa ~pb = (pb.y -. pa.y) /. (pb.x -. pa.x)
let huge_val = infinity
let hseg_intersect_seg ~s ~a ~b =
let _eps =
if s.y = (max a.y b.y) ||
s.y = (min a.y b.y) then 0.00001 else 0.0
in
if (s.y +. _eps) > (max a.y b.y) ||
(s.y +. _eps) < (min a.y b.y) ||
s.x > (max a.x b.x) then (false)
else if s.x <= (min a.x b.x) then (true)
else
let ca = if a.x <> b.x then (coeff_ang a b) else (huge_val) in
let my = min_y ~a ~b in
let cp = if (s.x -. my.x) <> 0.0 then (coeff_ang my s) else (huge_val) in
(cp >= ca)
;;
let point_is_inside ~poly ~pt =
let cross = ref 0 in
List.iter (fun (a,b) ->
if hseg_intersect_seg pt
poly.vertices.(a)
poly.vertices.(b)
then incr cross
) poly.edges;
( (!cross mod 2) <> 0)
;;
let make_test p label s =
Printf.printf "point (%.5f,%.5f) is " p.x p.y;
print_string (if point_is_inside s p
then "INSIDE "
else "OUTSIDE ");
print_endline label;
;;
let () =
let test_points = [
(p 5. 5.); (p 5. 8.); (p 2. 2.); (p 0. 0.);
(p 10. 10.); (p 2.5 2.5); (p 0.01 5.);
(p 2.2 7.4); (p 0. 5.); (p 10. 5.); (p (-4.) 10.) ] in
List.iter (fun p ->
make_test p "square" square;
make_test p "squarehole" squarehole;
make_test p "strange" strange;
make_test p "esa" esa;
print_newline()
) test_points;
;;