package geoml

  1. Overview
  2. Docs

Source file triangle.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
type t = Point.t * Point.t * Point.t

let of_points = Fun.id

let tri_map f ((pa, pb, pc) : t) = (f pa, f pb, f pc)

let print fmt (a, b, c) =
  Format.fprintf fmt "(%a, %a, %a)" Point.print a Point.print b Point.print c

let tri_exists f (pa, pb, pc) = f pa || f pb || f pc

let tri_find f ((pa, pb, pc) : t) =
  if f pa then pa
  else if f pb then pb
  else if f pc then pc
  else raise Not_found

let tri_forall f ((pa, pb, pc) : t) = f pa && f pb && f pc

let tri_iter f ((pa, pb, pc) : t) = f pa ; f pb ; f pc

let make p1 p2 p3 : t = (p1, p2, p3)

let extr1 ((p1, _, _) : t) = p1

let extr2 ((_, p2, _) : t) = p2

let extr3 ((_, _, p3) : t) = p3

let scale_x t f = tri_map (fun e -> Point.scale_x e f) t

let scale_y t f = tri_map (fun e -> Point.scale_y e f) t

let translate dx dy (tr : t) : t = tri_map (Point.translate dx dy) tr

let transform t m : t = tri_map (Point.transform m) t

let rotate (tr : t) p alpha : t =
  tri_map (fun p' -> Point.rotate p p' alpha) tr

let rotate_angle (tr : t) p alpha : t =
  tri_map (fun p' -> Point.rotate_angle p p' alpha) tr

let reflection p (tr : t) : t = tri_map (Point.reflection p) tr

(* tests if a point is in a triangle with barycentric coordinates *)
let contains (Point.({x= ax; y= ay}, {x= bx; y= by}, {x= cx; y= cy}) : t)
    Point.{x= px; y= py} =
  let bcy = by -. cy in
  let cbx = cx -. bx in
  let acx = ax -. cx in
  let acy = ay -. cy in
  let pcx = px -. cx in
  let pcy = py -. cy in
  let den = (bcy *. acx) +. (cbx *. acy) in
  let l1 = ((bcy *. pcx) +. (cbx *. pcy)) /. den
  and l2 = (((cy -. ay) *. pcx) +. (acx *. pcy)) /. den in
  let l3 = 1. -. l1 -. l2 in
  l3 > 0. && l3 < 1. && l2 > 0. && l2 < 1. && l1 > 0. && l1 < 1.

let area ((pa, pb, pc) : t) =
  let ab = Vector.of_points pa pb and ac = Vector.of_points pa pc in
  Vector.determinant ab ac *. 0.5

let perimeter ((pa, pb, pc) : t) =
  Point.distance pa pb +. Point.distance pb pc +. Point.distance pc pa

let proj_x ((pa, pb, pc) : t) =
  let open Point in
  let inf = min pa.x pb.x |> min pc.x and max = max pa.x pb.x |> max pc.x in
  (inf, max)

let proj_y ((pa, pb, pc) : t) =
  let open Point in
  let inf = min pa.y pb.y |> min pc.y and max = max pa.y pb.y |> max pc.y in
  (inf, max)

let segments ((pa, pb, pc) : t) =
  (Segment.make pa pb, Segment.make pb pc, Segment.make pc pa)

let intersects (s1 : t) (s2 : t) =
  let a, b, c = segments s1 and d, e, f = segments s2 in
  tri_exists
    (fun s ->
      Segment.intersects d s || Segment.intersects e s
      || Segment.intersects f s)
    (a, b, c)

let intersect_line (t : t) (l : Line.t) =
  let a, b, c = segments t in
  List.fold_left
    (fun acc s ->
      match Segment.intersect_line s l with
      | None -> acc
      | Some p -> p :: acc)
    [] [a; b; c]

let is_isoscele ((a, b, c) : t) =
  Point.sq_distance a b = Point.sq_distance b c
  || Point.sq_distance b c = Point.sq_distance a c
  || Point.sq_distance a b = Point.sq_distance a c

let is_equilateral ((a, b, c) : t) =
  Point.sq_distance a b = Point.sq_distance b c
  && Point.sq_distance b c = Point.sq_distance a c

let is_right ((a, b, c) : t) =
  let psq = Point.sq_distance in
  psq a b = psq b c +. psq c a
  || psq b c = psq a b +. psq c a
  || psq c a = psq a b +. psq b c

let points x = x

let angles ((pa, pb, pc) : t) =
  let open Vector in
  let a1 = angle_deg (of_points pa pb) (of_points pa pc) in
  let a2 = angle_deg (of_points pb pa) (of_points pb pc) in
  let a1 = abs_float a1 and a2 = abs_float a2 in
  let a3 = 180. -. (a1 +. a2) in
  (a1, a2, a3)

let centroid ((a, b, c) : t) =
  let bc = Point.center b c and ac = Point.center a c in
  let al = Line.of_points bc a and bl = Line.of_points ac b in
  Line.intersection bl al

let random_point st ((a, b, c) : t) : Point.t =
  let ab = Vector.of_points a b and ac = Vector.of_points a c in
  let r1 = Random.State.float st 1. in
  let r2 = Random.State.float st 1. in
  let r1, r2 = if r1 +. r2 <= 1. then (r1, r2) else (1. -. r1, 1. -. r2) in
  Vector.(move_to (add (scal_mult r1 ab) (scal_mult r2 ac))) a
OCaml

Innovation. Community. Security.